Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / app_controller_mac_browsertest.mm
1 // Copyright (c) 2012 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 #import <Carbon/Carbon.h>
6 #import <Cocoa/Cocoa.h>
7 #import <Foundation/Foundation.h>
8 #import <Foundation/NSAppleEventDescriptor.h>
9 #import <objc/message.h>
10 #import <objc/runtime.h>
11
12 #include "base/command_line.h"
13 #include "base/mac/foundation_util.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/run_loop.h"
17 #include "chrome/app/chrome_command_ids.h"
18 #import "chrome/browser/app_controller_mac.h"
19 #include "chrome/browser/apps/app_browsertest_util.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/host_desktop.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/browser/ui/user_manager.h"
28 #include "chrome/common/chrome_constants.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/test/base/in_process_browser_test.h"
33 #include "components/signin/core/common/profile_management_switches.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/test/test_navigation_observer.h"
36 #include "extensions/browser/app_window/app_window_registry.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/test/extension_test_message_listener.h"
39 #include "net/test/embedded_test_server/embedded_test_server.h"
40
41 namespace {
42
43 GURL g_open_shortcut_url = GURL::EmptyGURL();
44
45 // Returns an Apple Event that instructs the application to open |url|.
46 NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
47   NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
48       initWithEventClass:kASAppleScriptSuite
49                  eventID:kASSubroutineEvent
50         targetDescriptor:nil
51                 returnID:kAutoGenerateReturnID
52            transactionID:kAnyTransactionID] autorelease];
53   NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
54   [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
55                                          descriptorWithString:url_string]
56                           forKeyword:keyDirectObject];
57   return shortcut_event;
58 }
59
60 // Instructs the NSApp's delegate to open |url|.
61 void SendAppleEventToOpenUrlToAppController(const GURL& url) {
62   AppController* controller =
63       base::mac::ObjCCast<AppController>([NSApp delegate]);
64   Method get_url =
65       class_getInstanceMethod([controller class], @selector(getUrl:withReply:));
66
67   ASSERT_TRUE(get_url);
68
69   NSAppleEventDescriptor* shortcut_event = AppleEventToOpenUrl(url);
70
71   method_invoke(controller, get_url, shortcut_event, NULL);
72 }
73
74 }  // namespace
75
76 @interface TestOpenShortcutOnStartup : NSObject
77 - (void)applicationWillFinishLaunching:(NSNotification*)notification;
78 @end
79
80 @implementation TestOpenShortcutOnStartup
81
82 - (void)applicationWillFinishLaunching:(NSNotification*)notification {
83   if (!g_open_shortcut_url.is_valid())
84     return;
85
86   SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
87 }
88
89 @end
90
91 namespace {
92
93 class AppControllerPlatformAppBrowserTest
94     : public extensions::PlatformAppBrowserTest {
95  protected:
96   AppControllerPlatformAppBrowserTest()
97       : active_browser_list_(BrowserList::GetInstance(
98                                 chrome::GetActiveDesktop())) {
99   }
100
101   void SetUpCommandLine(CommandLine* command_line) override {
102     PlatformAppBrowserTest::SetUpCommandLine(command_line);
103     command_line->AppendSwitchASCII(switches::kAppId,
104                                     "1234");
105   }
106
107   const BrowserList* active_browser_list_;
108 };
109
110 // Test that if only a platform app window is open and no browser windows are
111 // open then a reopen event does nothing.
112 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
113                        PlatformAppReopenWithWindows) {
114   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
115   NSUInteger old_window_count = [[NSApp windows] count];
116   EXPECT_EQ(1u, active_browser_list_->size());
117   [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
118   // We do not EXPECT_TRUE the result here because the method
119   // deminiaturizes windows manually rather than return YES and have
120   // AppKit do it.
121
122   EXPECT_EQ(old_window_count, [[NSApp windows] count]);
123   EXPECT_EQ(1u, active_browser_list_->size());
124 }
125
126 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
127                        ActivationFocusesBrowserWindow) {
128   base::scoped_nsobject<AppController> app_controller(
129       [[AppController alloc] init]);
130
131   ExtensionTestMessageListener listener("Launched", false);
132   const extensions::Extension* app =
133       InstallAndLaunchPlatformApp("minimal");
134   ASSERT_TRUE(listener.WaitUntilSatisfied());
135
136   NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
137                              ->GetAppWindowsForApp(app->id())
138                              .front()
139                              ->GetNativeWindow();
140   NSWindow* browser_window = browser()->window()->GetNativeWindow();
141
142   EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
143             [[NSApp orderedWindows] indexOfObject:browser_window]);
144   [app_controller applicationShouldHandleReopen:NSApp
145                               hasVisibleWindows:YES];
146   EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
147             [[NSApp orderedWindows] indexOfObject:app_window]);
148 }
149
150 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
151  protected:
152   AppControllerWebAppBrowserTest()
153       : active_browser_list_(BrowserList::GetInstance(
154                                 chrome::GetActiveDesktop())) {
155   }
156
157   void SetUpCommandLine(CommandLine* command_line) override {
158     command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
159   }
160
161   std::string GetAppURL() const {
162     return "http://example.com/";
163   }
164
165   const BrowserList* active_browser_list_;
166 };
167
168 // Test that in web app mode a reopen event opens the app URL.
169 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
170                        WebAppReopenWithNoWindows) {
171   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
172   EXPECT_EQ(1u, active_browser_list_->size());
173   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
174
175   EXPECT_FALSE(result);
176   EXPECT_EQ(2u, active_browser_list_->size());
177
178   Browser* browser = active_browser_list_->get(0);
179   GURL current_url =
180       browser->tab_strip_model()->GetActiveWebContents()->GetURL();
181   EXPECT_EQ(GetAppURL(), current_url.spec());
182 }
183
184 // Called when the ProfileManager has created a profile.
185 void CreateProfileCallback(const base::Closure& quit_closure,
186                            Profile* profile,
187                            Profile::CreateStatus status) {
188   EXPECT_TRUE(profile);
189   EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
190   EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
191   // This will be called multiple times. Wait until the profile is initialized
192   // fully to quit the loop.
193   if (status == Profile::CREATE_STATUS_INITIALIZED)
194     quit_closure.Run();
195 }
196
197 void CreateAndWaitForGuestProfile() {
198   ProfileManager::CreateCallback create_callback =
199       base::Bind(&CreateProfileCallback,
200                  base::MessageLoop::current()->QuitClosure());
201   g_browser_process->profile_manager()->CreateProfileAsync(
202       ProfileManager::GetGuestProfilePath(),
203       create_callback,
204       base::string16(),
205       base::string16(),
206       std::string());
207   base::RunLoop().Run();
208 }
209
210 class AppControllerNewProfileManagementBrowserTest
211     : public InProcessBrowserTest {
212  protected:
213   AppControllerNewProfileManagementBrowserTest()
214       : active_browser_list_(BrowserList::GetInstance(
215                                 chrome::GetActiveDesktop())) {
216   }
217
218   void SetUpCommandLine(CommandLine* command_line) override {
219     switches::EnableNewProfileManagementForTesting(command_line);
220   }
221
222   const BrowserList* active_browser_list_;
223 };
224
225 // Test that for a regular last profile, a reopen event opens a browser.
226 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
227                        RegularProfileReopenWithNoWindows) {
228   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
229   EXPECT_EQ(1u, active_browser_list_->size());
230   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
231
232   EXPECT_FALSE(result);
233   EXPECT_EQ(2u, active_browser_list_->size());
234   EXPECT_FALSE(UserManager::IsShowing());
235 }
236
237 // Test that for a locked last profile, a reopen event opens the User Manager.
238 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
239                        LockedProfileReopenWithNoWindows) {
240   // The User Manager uses the guest profile as its underlying profile. To
241   // minimize flakiness due to the scheduling/descheduling of tasks on the
242   // different threads, pre-initialize the guest profile before it is needed.
243   CreateAndWaitForGuestProfile();
244   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
245
246   // Lock the active profile.
247   Profile* profile = [ac lastProfile];
248   ProfileInfoCache& cache =
249       g_browser_process->profile_manager()->GetProfileInfoCache();
250   size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
251   cache.SetProfileSigninRequiredAtIndex(profile_index, true);
252   EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(profile_index));
253
254   EXPECT_EQ(1u, active_browser_list_->size());
255   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
256   EXPECT_FALSE(result);
257
258   base::RunLoop().RunUntilIdle();
259   EXPECT_EQ(1u, active_browser_list_->size());
260   EXPECT_TRUE(UserManager::IsShowing());
261   UserManager::Hide();
262 }
263
264 // Test that for a guest last profile, a reopen event opens the User Manager.
265 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
266                        GuestProfileReopenWithNoWindows) {
267   // Create the guest profile, and set it as the last used profile so the
268   // app controller can use it on init.
269   CreateAndWaitForGuestProfile();
270   PrefService* local_state = g_browser_process->local_state();
271   local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
272
273   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
274
275   Profile* profile = [ac lastProfile];
276   EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
277   EXPECT_TRUE(profile->IsGuestSession());
278
279   EXPECT_EQ(1u, active_browser_list_->size());
280   BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
281   EXPECT_FALSE(result);
282
283   base::RunLoop().RunUntilIdle();
284
285   EXPECT_EQ(1u, active_browser_list_->size());
286   EXPECT_TRUE(UserManager::IsShowing());
287   UserManager::Hide();
288 }
289
290 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
291                        AboutChromeForcesUserManager) {
292   base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
293
294   // Create the guest profile, and set it as the last used profile so the
295   // app controller can use it on init.
296   CreateAndWaitForGuestProfile();
297   PrefService* local_state = g_browser_process->local_state();
298   local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
299
300   // Prohibiting guest mode forces the user manager flow for About Chrome.
301   local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
302
303   Profile* guest_profile = [ac lastProfile];
304   EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
305   EXPECT_TRUE(guest_profile->IsGuestSession());
306
307   // Tell the browser to open About Chrome.
308   EXPECT_EQ(1u, active_browser_list_->size());
309   [ac orderFrontStandardAboutPanel:NSApp];
310
311   base::RunLoop().RunUntilIdle();
312
313   // No new browser is opened; the User Manager opens instead.
314   EXPECT_EQ(1u, active_browser_list_->size());
315   EXPECT_TRUE(UserManager::IsShowing());
316
317   UserManager::Hide();
318 }
319
320 class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
321  protected:
322   AppControllerOpenShortcutBrowserTest() {
323   }
324
325   void SetUpInProcessBrowserTestFixture() override {
326     // In order to mimic opening shortcut during browser startup, we need to
327     // send the event before -applicationDidFinishLaunching is called, but
328     // after AppController is loaded.
329     //
330     // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
331     // our function to send the event. We need to do this early before running
332     // the main message loop.
333     //
334     // NSApp does not exist yet. We need to get the AppController using
335     // reflection.
336     Class appControllerClass = NSClassFromString(@"AppController");
337     Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
338
339     ASSERT_TRUE(appControllerClass != nil);
340     ASSERT_TRUE(openShortcutClass != nil);
341
342     SEL targetMethod = @selector(applicationWillFinishLaunching:);
343     Method original = class_getInstanceMethod(appControllerClass,
344         targetMethod);
345     Method destination = class_getInstanceMethod(openShortcutClass,
346         targetMethod);
347
348     ASSERT_TRUE(original != NULL);
349     ASSERT_TRUE(destination != NULL);
350
351     method_exchangeImplementations(original, destination);
352
353     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
354     g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
355   }
356
357   void SetUpCommandLine(CommandLine* command_line) override {
358     // If the arg is empty, PrepareTestCommandLine() after this function will
359     // append about:blank as default url.
360     command_line->AppendArg(chrome::kChromeUINewTabURL);
361   }
362 };
363
364 IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
365                        OpenShortcutOnStartup) {
366   EXPECT_EQ(1, browser()->tab_strip_model()->count());
367   EXPECT_EQ(g_open_shortcut_url,
368       browser()->tab_strip_model()->GetActiveWebContents()
369           ->GetLastCommittedURL());
370 }
371
372 class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
373  protected:
374   AppControllerReplaceNTPBrowserTest() {}
375
376   void SetUpInProcessBrowserTestFixture() override {
377     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
378   }
379
380   void SetUpCommandLine(CommandLine* command_line) override {
381     // If the arg is empty, PrepareTestCommandLine() after this function will
382     // append about:blank as default url.
383     command_line->AppendArg(chrome::kChromeUINewTabURL);
384   }
385 };
386
387 // Tests that when a GURL is opened after startup, it replaces the NTP.
388 IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
389                        ReplaceNTPAfterStartup) {
390   // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
391   GURL ntp(chrome::kChromeUINewTabURL);
392   EXPECT_EQ(1, browser()->tab_strip_model()->count());
393   EXPECT_EQ(ntp,
394             browser()
395                 ->tab_strip_model()
396                 ->GetActiveWebContents()
397                 ->GetLastCommittedURL());
398
399   GURL simple(embedded_test_server()->GetURL("/simple.html"));
400   SendAppleEventToOpenUrlToAppController(simple);
401
402   // Wait for one navigation on the active web contents.
403   EXPECT_EQ(1, browser()->tab_strip_model()->count());
404   content::TestNavigationObserver obs(
405       browser()->tab_strip_model()->GetActiveWebContents(), 1);
406   obs.Wait();
407
408   EXPECT_EQ(simple,
409             browser()
410                 ->tab_strip_model()
411                 ->GetActiveWebContents()
412                 ->GetLastCommittedURL());
413 }
414
415 }  // namespace