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/launcher.h"
6#include "base/bind.h"
7#include "base/command_line.h"
8#include "base/files/file_util.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/prefs/pref_service.h"
11#include "base/stl_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/app/chrome_command_ids.h"
14#include "chrome/browser/apps/app_browsertest_util.h"
15#include "chrome/browser/chrome_notification_types.h"
16#include "chrome/browser/devtools/devtools_window.h"
17#include "chrome/browser/extensions/api/permissions/permissions_api.h"
18#include "chrome/browser/extensions/component_loader.h"
19#include "chrome/browser/extensions/extension_browsertest.h"
20#include "chrome/browser/extensions/extension_service.h"
21#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
22#include "chrome/browser/ui/browser.h"
23#include "chrome/browser/ui/extensions/application_launch.h"
24#include "chrome/browser/ui/tabs/tab_strip_model.h"
25#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
26#include "chrome/common/chrome_switches.h"
27#include "chrome/common/pref_names.h"
28#include "chrome/common/url_constants.h"
29#include "chrome/test/base/test_switches.h"
30#include "chrome/test/base/ui_test_utils.h"
31#include "components/pref_registry/pref_registry_syncable.h"
32#include "components/web_modal/web_contents_modal_dialog_manager.h"
33#include "content/public/browser/devtools_agent_host.h"
34#include "content/public/browser/render_process_host.h"
35#include "content/public/browser/render_widget_host_view.h"
36#include "content/public/test/test_utils.h"
37#include "extensions/browser/app_window/app_window.h"
38#include "extensions/browser/app_window/app_window_registry.h"
39#include "extensions/browser/app_window/native_app_window.h"
40#include "extensions/browser/event_router.h"
41#include "extensions/browser/extension_prefs.h"
42#include "extensions/browser/extension_system.h"
43#include "extensions/browser/notification_types.h"
44#include "extensions/browser/pref_names.h"
45#include "extensions/common/api/app_runtime.h"
46#include "extensions/test/extension_test_message_listener.h"
47#include "extensions/test/result_catcher.h"
48#include "net/test/embedded_test_server/embedded_test_server.h"
49#include "url/gurl.h"
50
51#if defined(OS_CHROMEOS)
52#include "base/memory/scoped_ptr.h"
53#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
54#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
55#include "chromeos/dbus/dbus_thread_manager.h"
56#include "chromeos/dbus/fake_power_manager_client.h"
57#endif
58
59using content::WebContents;
60using web_modal::WebContentsModalDialogManager;
61
62namespace app_runtime = extensions::core_api::app_runtime;
63
64namespace extensions {
65
66namespace {
67
68// Non-abstract RenderViewContextMenu class.
69class PlatformAppContextMenu : public RenderViewContextMenu {
70 public:
71  PlatformAppContextMenu(content::RenderFrameHost* render_frame_host,
72                         const content::ContextMenuParams& params)
73      : RenderViewContextMenu(render_frame_host, params) {}
74
75  bool HasCommandWithId(int command_id) {
76    return menu_model_.GetIndexOfCommandId(command_id) != -1;
77  }
78
79 protected:
80  // RenderViewContextMenu implementation.
81  virtual bool GetAcceleratorForCommandId(
82      int command_id,
83      ui::Accelerator* accelerator) OVERRIDE {
84    return false;
85  }
86};
87
88// This class keeps track of tabs as they are added to the browser. It will be
89// "done" (i.e. won't block on Wait()) once |observations| tabs have been added.
90class TabsAddedNotificationObserver
91    : public content::WindowedNotificationObserver {
92 public:
93  explicit TabsAddedNotificationObserver(size_t observations)
94      : content::WindowedNotificationObserver(
95            chrome::NOTIFICATION_TAB_ADDED,
96            content::NotificationService::AllSources()),
97        observations_(observations) {
98  }
99
100  virtual void Observe(int type,
101                       const content::NotificationSource& source,
102                       const content::NotificationDetails& details) OVERRIDE {
103    observed_tabs_.push_back(
104        content::Details<WebContents>(details).ptr());
105    if (observed_tabs_.size() == observations_)
106      content::WindowedNotificationObserver::Observe(type, source, details);
107  }
108
109  const std::vector<content::WebContents*>& tabs() { return observed_tabs_; }
110
111 private:
112  size_t observations_;
113  std::vector<content::WebContents*> observed_tabs_;
114
115  DISALLOW_COPY_AND_ASSIGN(TabsAddedNotificationObserver);
116};
117
118#if defined(ENABLE_FULL_PRINTING)
119class ScopedPreviewTestingDelegate : PrintPreviewUI::TestingDelegate {
120 public:
121  explicit ScopedPreviewTestingDelegate(bool auto_cancel)
122      : auto_cancel_(auto_cancel),
123        total_page_count_(1),
124        rendered_page_count_(0) {
125    PrintPreviewUI::SetDelegateForTesting(this);
126  }
127
128  ~ScopedPreviewTestingDelegate() {
129    PrintPreviewUI::SetDelegateForTesting(NULL);
130  }
131
132  // PrintPreviewUI::TestingDelegate implementation.
133  virtual bool IsAutoCancelEnabled() OVERRIDE {
134    return auto_cancel_;
135  }
136
137  // PrintPreviewUI::TestingDelegate implementation.
138  virtual void DidGetPreviewPageCount(int page_count) OVERRIDE {
139    total_page_count_ = page_count;
140  }
141
142  // PrintPreviewUI::TestingDelegate implementation.
143  virtual void DidRenderPreviewPage(content::WebContents* preview_dialog)
144      OVERRIDE {
145    dialog_size_ = preview_dialog->GetContainerBounds().size();
146    ++rendered_page_count_;
147    CHECK(rendered_page_count_ <= total_page_count_);
148    if (waiting_runner_.get() && rendered_page_count_ == total_page_count_) {
149      waiting_runner_->Quit();
150    }
151  }
152
153  void WaitUntilPreviewIsReady() {
154    CHECK(!waiting_runner_.get());
155    if (rendered_page_count_ < total_page_count_) {
156      waiting_runner_ = new content::MessageLoopRunner;
157      waiting_runner_->Run();
158      waiting_runner_ = NULL;
159    }
160  }
161
162  gfx::Size dialog_size() {
163    return dialog_size_;
164  }
165
166 private:
167  bool auto_cancel_;
168  int total_page_count_;
169  int rendered_page_count_;
170  scoped_refptr<content::MessageLoopRunner> waiting_runner_;
171  gfx::Size dialog_size_;
172};
173
174#endif  // ENABLE_FULL_PRINTING
175
176#if !defined(OS_CHROMEOS) && !defined(OS_WIN)
177bool CopyTestDataAndSetCommandLineArg(
178    const base::FilePath& test_data_file,
179    const base::FilePath& temp_dir,
180    const char* filename) {
181  base::FilePath path = temp_dir.AppendASCII(
182      filename).NormalizePathSeparators();
183  if (!(base::CopyFile(test_data_file, path)))
184    return false;
185
186  CommandLine* command_line = CommandLine::ForCurrentProcess();
187  command_line->AppendArgPath(path);
188  return true;
189}
190#endif  // !defined(OS_CHROMEOS) && !defined(OS_WIN)
191
192#if !defined(OS_CHROMEOS)
193const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
194#endif
195
196}  // namespace
197
198// Tests that CreateAppWindow doesn't crash if you close it straight away.
199// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
200// ash, so we test that it works here.
201IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseAppWindow) {
202  const Extension* extension = LoadAndLaunchPlatformApp("minimal", "Launched");
203  AppWindow* window = CreateAppWindow(extension);
204  CloseAppWindow(window);
205}
206
207// Tests that platform apps received the "launch" event when launched.
208IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
209  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
210}
211
212// Tests that platform apps cannot use certain disabled window properties, but
213// can override them and then use them.
214IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
215  ASSERT_TRUE(RunPlatformAppTest("platform_apps/disabled_window_properties"))
216      << message_;
217}
218
219IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
220  LoadAndLaunchPlatformApp("minimal", "Launched");
221
222  // The empty app doesn't add any context menu items, so its menu should
223  // only include the developer tools.
224  WebContents* web_contents = GetFirstAppWindowWebContents();
225  ASSERT_TRUE(web_contents);
226  content::ContextMenuParams params;
227  scoped_ptr<PlatformAppContextMenu> menu;
228  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
229  menu->Init();
230  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
231  ASSERT_TRUE(
232      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
233  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
234  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
235  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
236}
237
238IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
239  LoadAndLaunchPlatformApp("context_menu", "Launched");
240
241  // The context_menu app has two context menu items. These, along with a
242  // separator and the developer tools, is all that should be in the menu.
243  WebContents* web_contents = GetFirstAppWindowWebContents();
244  ASSERT_TRUE(web_contents);
245  content::ContextMenuParams params;
246  scoped_ptr<PlatformAppContextMenu> menu;
247  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
248  menu->Init();
249  int first_extensions_command_id =
250      ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
251  ASSERT_TRUE(menu->HasCommandWithId(first_extensions_command_id));
252  ASSERT_TRUE(menu->HasCommandWithId(first_extensions_command_id + 1));
253  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
254  ASSERT_TRUE(
255      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
256  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
257  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
258  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
259  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
260}
261
262IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
263  ExtensionTestMessageListener launched_listener("Launched", false);
264  InstallAndLaunchPlatformApp("context_menu");
265
266  // Wait for the extension to tell us it's initialized its context menus and
267  // launched a window.
268  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
269
270  // The context_menu app has two context menu items. For an installed app
271  // these are all that should be in the menu.
272  WebContents* web_contents = GetFirstAppWindowWebContents();
273  ASSERT_TRUE(web_contents);
274  content::ContextMenuParams params;
275  scoped_ptr<PlatformAppContextMenu> menu;
276  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
277  menu->Init();
278  int extensions_custom_id =
279      ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
280  ASSERT_TRUE(menu->HasCommandWithId(extensions_custom_id));
281  ASSERT_TRUE(menu->HasCommandWithId(extensions_custom_id + 1));
282  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
283  ASSERT_FALSE(
284      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
285  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
286  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
287  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
288  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
289}
290
291IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
292  LoadAndLaunchPlatformApp("context_menu", "Launched");
293
294  // The context_menu app has one context menu item. This, along with a
295  // separator and the developer tools, is all that should be in the menu.
296  WebContents* web_contents = GetFirstAppWindowWebContents();
297  ASSERT_TRUE(web_contents);
298  content::ContextMenuParams params;
299  params.is_editable = true;
300  scoped_ptr<PlatformAppContextMenu> menu;
301  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
302  menu->Init();
303  int extensions_custom_id =
304      ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
305  ASSERT_TRUE(menu->HasCommandWithId(extensions_custom_id));
306  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
307  ASSERT_TRUE(
308      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
309  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
310  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
311  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
312  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
313  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
314}
315
316IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
317  LoadAndLaunchPlatformApp("context_menu", "Launched");
318
319  // The context_menu app has one context menu item. This, along with a
320  // separator and the developer tools, is all that should be in the menu.
321  WebContents* web_contents = GetFirstAppWindowWebContents();
322  ASSERT_TRUE(web_contents);
323  content::ContextMenuParams params;
324  params.selection_text = base::ASCIIToUTF16("Hello World");
325  scoped_ptr<PlatformAppContextMenu> menu;
326  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
327  menu->Init();
328  int extensions_custom_id =
329      ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
330  ASSERT_TRUE(menu->HasCommandWithId(extensions_custom_id));
331  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
332  ASSERT_TRUE(
333      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
334  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
335  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
336  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
337  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
338  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
339}
340
341IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
342  LoadAndLaunchPlatformApp("context_menu_click", "Launched");
343
344  // Test that the menu item shows up
345  WebContents* web_contents = GetFirstAppWindowWebContents();
346  ASSERT_TRUE(web_contents);
347  content::ContextMenuParams params;
348  params.page_url = GURL("http://foo.bar");
349  scoped_ptr<PlatformAppContextMenu> menu;
350  menu.reset(new PlatformAppContextMenu(web_contents->GetMainFrame(), params));
351  menu->Init();
352  int extensions_custom_id =
353      ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
354  ASSERT_TRUE(menu->HasCommandWithId(extensions_custom_id));
355
356  // Execute the menu item
357  ExtensionTestMessageListener onclicked_listener("onClicked fired for id1",
358                                                  false);
359  menu->ExecuteCommand(extensions_custom_id, 0);
360
361  ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
362}
363
364#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
365// TODO(erg): linux_aura bringup: http://crbug.com/163931
366#define MAYBE_DisallowNavigation DISABLED_DisallowNavigation
367#else
368#define MAYBE_DisallowNavigation DisallowNavigation
369#endif
370
371IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_DisallowNavigation) {
372  TabsAddedNotificationObserver observer(2);
373
374  ASSERT_TRUE(StartEmbeddedTestServer());
375  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
376
377  observer.Wait();
378  ASSERT_EQ(2U, observer.tabs().size());
379  EXPECT_EQ(std::string(chrome::kExtensionInvalidRequestURL),
380            observer.tabs()[0]->GetURL().spec());
381  EXPECT_EQ("http://chromium.org/",
382            observer.tabs()[1]->GetURL().spec());
383}
384
385// Failing on some Win and Linux buildbots.  See crbug.com/354425.
386#if defined(OS_WIN) || defined(OS_LINUX)
387#define MAYBE_Iframes DISABLED_Iframes
388#else
389#define MAYBE_Iframes Iframes
390#endif
391IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Iframes) {
392  ASSERT_TRUE(StartEmbeddedTestServer());
393  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
394}
395
396// Tests that localStorage and WebSQL are disabled for platform apps.
397IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
398  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
399}
400
401IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
402  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
403}
404
405// Tests that extensions can't use platform-app-only APIs.
406IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) {
407  ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings(
408      "platform_apps/apps_only")) << message_;
409}
410
411// Tests that platform apps have isolated storage by default.
412IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
413  ASSERT_TRUE(StartEmbeddedTestServer());
414
415  // Load a (non-app) page under the "localhost" origin that sets a cookie.
416  GURL set_cookie_url = embedded_test_server()->GetURL(
417      "/extensions/platform_apps/isolation/set_cookie.html");
418  GURL::Replacements replace_host;
419  std::string host_str("localhost");  // Must stay in scope with replace_host.
420  replace_host.SetHostStr(host_str);
421  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
422
423  ui_test_utils::NavigateToURLWithDisposition(
424      browser(), set_cookie_url,
425      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
426
427  // Make sure the cookie is set.
428  int cookie_size;
429  std::string cookie_value;
430  ui_test_utils::GetCookies(
431      set_cookie_url,
432      browser()->tab_strip_model()->GetWebContentsAt(0),
433      &cookie_size,
434      &cookie_value);
435  ASSERT_EQ("testCookie=1", cookie_value);
436
437  // Let the platform app request the same URL, and make sure that it doesn't
438  // see the cookie.
439  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
440}
441
442// See crbug.com/248441
443#if defined(OS_WIN)
444#define MAYBE_ExtensionWindowingApis DISABLED_ExtensionWindowingApis
445#else
446#define MAYBE_ExtensionWindowingApis ExtensionWindowingApis
447#endif
448
449IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ExtensionWindowingApis) {
450  // Initially there should be just the one browser window visible to the
451  // extensions API.
452  const Extension* extension = LoadExtension(
453      test_data_dir_.AppendASCII("common/background_page"));
454  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
455
456  // And no app windows.
457  ASSERT_EQ(0U, GetAppWindowCount());
458
459  // Launch a platform app that shows a window.
460  LoadAndLaunchPlatformApp("minimal", "Launched");
461  ASSERT_EQ(1U, GetAppWindowCount());
462  int app_window_id = GetFirstAppWindow()->session_id().id();
463
464  // But it's not visible to the extensions API, it still thinks there's just
465  // one browser window.
466  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
467  // It can't look it up by ID either
468  ASSERT_FALSE(RunGetWindowFunctionForExtension(app_window_id, extension));
469
470  // The app can also only see one window (its own).
471  // TODO(jeremya): add an extension function to get an app window by ID, and
472  // to get a list of all the app windows, so we can test this.
473
474  // Launch another platform app that also shows a window.
475  LoadAndLaunchPlatformApp("context_menu", "Launched");
476
477  // There are two total app windows, but each app can only see its own.
478  ASSERT_EQ(2U, GetAppWindowCount());
479  // TODO(jeremya): as above, this requires more extension functions.
480}
481
482// ChromeOS does not support passing arguments on the command line, so the tests
483// that rely on this functionality are disabled.
484#if !defined(OS_CHROMEOS)
485// Tests that command line parameters get passed through to platform apps
486// via launchData correctly when launching with a file.
487// TODO(benwells/jeremya): tests need a way to specify a handler ID.
488IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
489  SetCommandLineArg(kTestFilePath);
490  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
491      << message_;
492}
493
494// Tests that relative paths can be passed through to the platform app.
495// This test doesn't use the normal test infrastructure as it needs to open
496// the application differently to all other platform app tests, by setting
497// the AppLaunchParams.current_directory field.
498IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
499  // Setup the command line
500  ClearCommandLineArgs();
501  CommandLine* command_line = CommandLine::ForCurrentProcess();
502  base::FilePath relative_test_doc =
503      base::FilePath::FromUTF8Unsafe(kTestFilePath);
504  relative_test_doc = relative_test_doc.NormalizePathSeparators();
505  command_line->AppendArgPath(relative_test_doc);
506
507  // Load the extension
508  ResultCatcher catcher;
509  const Extension* extension = LoadExtension(
510      test_data_dir_.AppendASCII("platform_apps/launch_file"));
511  ASSERT_TRUE(extension);
512
513  // Run the test
514  AppLaunchParams params(
515      browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW);
516  params.command_line = *CommandLine::ForCurrentProcess();
517  params.current_directory = test_data_dir_;
518  OpenApplication(params);
519
520  if (!catcher.GetNextResult()) {
521    message_ = catcher.message();
522    ASSERT_TRUE(0);
523  }
524}
525
526// Tests that launch data is sent through if the file extension matches.
527IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileExtension) {
528  SetCommandLineArg(kTestFilePath);
529  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_by_extension"))
530      << message_;
531}
532
533// Tests that launch data is sent through to a whitelisted extension if the file
534// extension matches.
535IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
536                       LaunchWhiteListedExtensionWithFile) {
537  SetCommandLineArg(kTestFilePath);
538  ASSERT_TRUE(RunPlatformAppTest(
539      "platform_apps/launch_whitelisted_ext_with_file"))
540          << message_;
541}
542
543#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
544// TODO(erg): linux_aura bringup: http://crbug.com/163931
545#define MAYBE_LaunchWithFileExtensionAndMimeType DISABLED_LaunchWithFileExtensionAndMimeType
546#else
547#define MAYBE_LaunchWithFileExtensionAndMimeType LaunchWithFileExtensionAndMimeType
548#endif
549
550// Tests that launch data is sent through if the file extension and MIME type
551// both match.
552IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
553                       MAYBE_LaunchWithFileExtensionAndMimeType) {
554  SetCommandLineArg(kTestFilePath);
555  ASSERT_TRUE(RunPlatformAppTest(
556      "platform_apps/launch_file_by_extension_and_type")) << message_;
557}
558
559// Tests that launch data is sent through for a file with no extension if a
560// handler accepts "".
561IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileWithoutExtension) {
562  SetCommandLineArg("platform_apps/launch_files/test");
563  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
564      << message_;
565}
566
567#if !defined(OS_WIN)
568// Tests that launch data is sent through for a file with an empty extension if
569// a handler accepts "".
570IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileEmptyExtension) {
571  base::ScopedTempDir temp_dir;
572  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
573  ClearCommandLineArgs();
574  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
575      test_data_dir_.AppendASCII(kTestFilePath),
576      temp_dir.path(),
577      "test."));
578  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
579      << message_;
580}
581
582// Tests that launch data is sent through for a file with an empty extension if
583// a handler accepts *.
584IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
585                       LaunchWithFileEmptyExtensionAcceptAny) {
586  base::ScopedTempDir temp_dir;
587  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
588  ClearCommandLineArgs();
589  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
590      test_data_dir_.AppendASCII(kTestFilePath),
591      temp_dir.path(),
592      "test."));
593  ASSERT_TRUE(RunPlatformAppTest(
594      "platform_apps/launch_file_with_any_extension")) << message_;
595}
596#endif
597
598// Tests that launch data is sent through for a file with no extension if a
599// handler accepts *.
600IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
601                       LaunchWithFileWithoutExtensionAcceptAny) {
602  SetCommandLineArg("platform_apps/launch_files/test");
603  ASSERT_TRUE(RunPlatformAppTest(
604      "platform_apps/launch_file_with_any_extension")) << message_;
605}
606
607// Tests that launch data is sent through for a file with an extension if a
608// handler accepts *.
609IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
610                       LaunchWithFileAcceptAnyExtension) {
611  SetCommandLineArg(kTestFilePath);
612  ASSERT_TRUE(RunPlatformAppTest(
613      "platform_apps/launch_file_with_any_extension")) << message_;
614}
615
616// Tests that no launch data is sent through if the file has the wrong
617// extension.
618IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongExtension) {
619  SetCommandLineArg(kTestFilePath);
620  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
621      << message_;
622}
623
624// Tests that no launch data is sent through if the file has no extension but
625// the handler requires a specific extension.
626IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongEmptyExtension) {
627  SetCommandLineArg("platform_apps/launch_files/test");
628  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
629      << message_;
630}
631
632// Tests that no launch data is sent through if the file is of the wrong MIME
633// type.
634IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
635  SetCommandLineArg(kTestFilePath);
636  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
637      << message_;
638}
639
640// Tests that no launch data is sent through if the platform app does not
641// provide an intent.
642IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
643  SetCommandLineArg(kTestFilePath);
644  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
645      << message_;
646}
647
648// Tests that launch data is sent through when the file has unknown extension
649// but the MIME type can be sniffed and the sniffed type matches.
650IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithSniffableType) {
651  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
652  ASSERT_TRUE(RunPlatformAppTest(
653      "platform_apps/launch_file_by_extension_and_type")) << message_;
654}
655
656// Tests that launch data is sent through with the MIME type set to
657// application/octet-stream if the file MIME type cannot be read.
658IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
659  SetCommandLineArg("platform_apps/launch_files/test_binary.unknownextension");
660  ASSERT_TRUE(RunPlatformAppTest(
661      "platform_apps/launch_application_octet_stream")) << message_;
662}
663
664// Tests that no launch data is sent through if the file does not exist.
665IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
666  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
667  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
668      << message_;
669}
670
671// Tests that no launch data is sent through if the argument is a directory.
672IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
673  SetCommandLineArg("platform_apps/launch_files");
674  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
675      << message_;
676}
677
678// Tests that no launch data is sent through if there are no arguments passed
679// on the command line
680IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
681  ClearCommandLineArgs();
682  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
683      << message_;
684}
685
686// Test that platform apps can use the chrome.fileSystem.getDisplayPath
687// function to get the native file system path of a file they are launched with.
688IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
689  SetCommandLineArg(kTestFilePath);
690  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
691      << message_;
692}
693
694// Tests that the file is created if the file does not exist and the app has the
695// fileSystem.write permission.
696IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNewFile) {
697  base::ScopedTempDir temp_dir;
698  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
699  ClearCommandLineArgs();
700  CommandLine* command_line = CommandLine::ForCurrentProcess();
701  command_line->AppendArgPath(temp_dir.path().AppendASCII("new_file.txt"));
702  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_new_file")) << message_;
703}
704
705#endif  // !defined(OS_CHROMEOS)
706
707IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
708  ASSERT_TRUE(StartEmbeddedTestServer());
709  content::WindowedNotificationObserver observer(
710      chrome::NOTIFICATION_TAB_ADDED,
711      content::Source<content::WebContentsDelegate>(browser()));
712  LoadAndLaunchPlatformApp("open_link", "Launched");
713  observer.Wait();
714  ASSERT_EQ(2, browser()->tab_strip_model()->count());
715}
716
717IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
718  ASSERT_TRUE(RunPlatformAppTest("platform_apps/mutation_events")) << message_;
719}
720
721// This appears to be unreliable on linux.
722// TODO(stevenjb): Investigate and enable
723#if defined(OS_LINUX) && !defined(USE_ASH)
724#define MAYBE_AppWindowRestoreState DISABLED_AppWindowRestoreState
725#else
726#define MAYBE_AppWindowRestoreState AppWindowRestoreState
727#endif
728IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_AppWindowRestoreState) {
729  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
730}
731
732IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
733                       AppWindowAdjustBoundsToBeVisibleOnScreen) {
734  const Extension* extension = LoadAndLaunchPlatformApp("minimal", "Launched");
735
736  AppWindow* window = CreateAppWindow(extension);
737
738  // The screen bounds didn't change, the cached bounds didn't need to adjust.
739  gfx::Rect cached_bounds(80, 100, 400, 400);
740  gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
741  gfx::Rect current_screen_bounds(0, 0, 1600, 900);
742  gfx::Size minimum_size(200, 200);
743  gfx::Rect bounds;
744  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(window,
745                                                  cached_bounds,
746                                                  cached_screen_bounds,
747                                                  current_screen_bounds,
748                                                  minimum_size,
749                                                  &bounds);
750  EXPECT_EQ(bounds, cached_bounds);
751
752  // We have an empty screen bounds, the cached bounds didn't need to adjust.
753  gfx::Rect empty_screen_bounds;
754  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(window,
755                                                  cached_bounds,
756                                                  empty_screen_bounds,
757                                                  current_screen_bounds,
758                                                  minimum_size,
759                                                  &bounds);
760  EXPECT_EQ(bounds, cached_bounds);
761
762  // Cached bounds is completely off the new screen bounds in horizontal
763  // locations. Expect to reposition the bounds.
764  gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
765  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(
766      window,
767      horizontal_out_of_screen_bounds,
768      gfx::Rect(-1366, 0, 1600, 900),
769      current_screen_bounds,
770      minimum_size,
771      &bounds);
772  EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
773
774  // Cached bounds is completely off the new screen bounds in vertical
775  // locations. Expect to reposition the bounds.
776  gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
777  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(
778      window,
779      vertical_out_of_screen_bounds,
780      gfx::Rect(-1366, 0, 1600, 900),
781      current_screen_bounds,
782      minimum_size,
783      &bounds);
784  EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
785
786  // From a large screen resulotion to a small one. Expect it fit on screen.
787  gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
788  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(window,
789                                                  big_cache_bounds,
790                                                  gfx::Rect(0, 0, 1600, 1000),
791                                                  gfx::Rect(0, 0, 800, 600),
792                                                  minimum_size,
793                                                  &bounds);
794  EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
795
796  // Don't resize the bounds smaller than minimum size, when the minimum size is
797  // larger than the screen.
798  CallAdjustBoundsToBeVisibleOnScreenForAppWindow(window,
799                                                  big_cache_bounds,
800                                                  gfx::Rect(0, 0, 1600, 1000),
801                                                  gfx::Rect(0, 0, 800, 600),
802                                                  gfx::Size(900, 900),
803                                                  &bounds);
804  EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
805}
806
807namespace {
808
809class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
810 protected:
811  enum TestFlags {
812    RELAUNCH = 0x1,
813    HAS_ID = 0x2,
814  };
815  // Runs a test inside a harness that opens DevTools on an app window.
816  void RunTestWithDevTools(const char* name, int test_flags);
817};
818
819void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
820    const char* name, int test_flags) {
821  using content::DevToolsAgentHost;
822  const Extension* extension = LoadAndLaunchPlatformApp(name, "Launched");
823  ASSERT_TRUE(extension);
824  AppWindow* window = GetFirstAppWindow();
825  ASSERT_TRUE(window);
826  ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
827  content::WebContents* web_contents = window->web_contents();
828  ASSERT_TRUE(web_contents);
829
830  // Ensure no DevTools open for the AppWindow, then open one.
831  ASSERT_FALSE(DevToolsAgentHost::HasFor(web_contents));
832  DevToolsWindow::OpenDevToolsWindow(web_contents);
833  ASSERT_TRUE(DevToolsAgentHost::HasFor(web_contents));
834
835  if (test_flags & RELAUNCH) {
836    // Close the AppWindow, and ensure it is gone.
837    CloseAppWindow(window);
838    ASSERT_FALSE(GetFirstAppWindow());
839
840    // Relaunch the app and get a new AppWindow.
841    content::WindowedNotificationObserver app_loaded_observer(
842        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
843        content::NotificationService::AllSources());
844    OpenApplication(AppLaunchParams(
845        browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
846    app_loaded_observer.Wait();
847    window = GetFirstAppWindow();
848    ASSERT_TRUE(window);
849
850    // DevTools should have reopened with the relaunch.
851    web_contents = window->web_contents();
852    ASSERT_TRUE(web_contents);
853    ASSERT_TRUE(DevToolsAgentHost::HasFor(web_contents));
854  }
855}
856
857}  // namespace
858
859// http://crbug.com/246634
860#if defined(OS_CHROMEOS)
861#define MAYBE_ReOpenedWithID DISABLED_ReOpenedWithID
862#else
863#define MAYBE_ReOpenedWithID ReOpenedWithID
864#endif
865IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
866#if defined(OS_WIN) && defined(USE_ASH)
867  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
868  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
869    return;
870#endif
871  RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
872}
873
874// http://crbug.com/246999
875#if defined(OS_CHROMEOS) || defined(OS_WIN)
876#define MAYBE_ReOpenedWithURL DISABLED_ReOpenedWithURL
877#else
878#define MAYBE_ReOpenedWithURL ReOpenedWithURL
879#endif
880IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithURL) {
881  RunTestWithDevTools("minimal", RELAUNCH);
882}
883
884// Test that showing a permission request as a constrained window works and is
885// correctly parented.
886#if defined(OS_MACOSX)
887#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
888#else
889// TODO(sail): Enable this on other platforms once http://crbug.com/95455 is
890// fixed.
891#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
892#endif
893
894IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
895  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
896  const Extension* extension =
897      LoadAndLaunchPlatformApp("optional_permission_request", "Launched");
898  ASSERT_TRUE(extension) << "Failed to load extension.";
899
900  WebContents* web_contents = GetFirstAppWindowWebContents();
901  ASSERT_TRUE(web_contents);
902
903  // Verify that the app window has a dialog attached.
904  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
905      WebContentsModalDialogManager::FromWebContents(web_contents);
906  EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
907
908  // Close the constrained window and wait for the reply to the permission
909  // request.
910  ExtensionTestMessageListener listener("PermissionRequestDone", false);
911  WebContentsModalDialogManager::TestApi test_api(
912      web_contents_modal_dialog_manager);
913  test_api.CloseAllDialogs();
914  ASSERT_TRUE(listener.WaitUntilSatisfied());
915}
916
917// Tests that an app calling chrome.runtime.reload will reload the app and
918// relaunch it if it was running.
919IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
920  ExtensionTestMessageListener launched_listener("Launched", true);
921  const Extension* extension =
922      LoadAndLaunchPlatformApp("reload", &launched_listener);
923  ASSERT_TRUE(extension);
924  ASSERT_TRUE(GetFirstAppWindow());
925
926  // Now tell the app to reload itself
927  ExtensionTestMessageListener launched_listener2("Launched", false);
928  launched_listener.Reply("reload");
929  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
930  ASSERT_TRUE(GetFirstAppWindow());
931}
932
933namespace {
934
935// Simple observer to check for
936// NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED events to ensure
937// installation does or does not occur in certain scenarios.
938class CheckExtensionInstalledObserver : public content::NotificationObserver {
939 public:
940  CheckExtensionInstalledObserver() : seen_(false) {
941    registrar_.Add(
942        this,
943        extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED,
944        content::NotificationService::AllSources());
945  }
946
947  bool seen() const {
948    return seen_;
949  };
950
951  // NotificationObserver:
952  virtual void Observe(int type,
953                       const content::NotificationSource& source,
954                       const content::NotificationDetails& details) OVERRIDE {
955    EXPECT_FALSE(seen_);
956    seen_ = true;
957  }
958
959 private:
960  bool seen_;
961  content::NotificationRegistrar registrar_;
962};
963
964}  // namespace
965
966// Component App Test 1 of 3: ensure that the initial load of a component
967// extension utilizing a background page (e.g. a v2 platform app) has its
968// background page run and is launchable. Waits for the Launched response from
969// the script resource in the opened app window.
970IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
971                       PRE_PRE_ComponentAppBackgroundPage) {
972  CheckExtensionInstalledObserver should_install;
973
974  // Ensure that we wait until the background page is run (to register the
975  // OnLaunched listener) before trying to open the application. This is similar
976  // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
977  content::WindowedNotificationObserver app_loaded_observer(
978      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
979      content::NotificationService::AllSources());
980
981  const Extension* extension = LoadExtensionAsComponent(
982      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
983  ASSERT_TRUE(extension);
984
985  app_loaded_observer.Wait();
986  ASSERT_TRUE(should_install.seen());
987
988  ExtensionTestMessageListener launched_listener("Launched", false);
989  OpenApplication(AppLaunchParams(
990      browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
991
992  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
993}
994
995// Component App Test 2 of 3: ensure an installed component app can be launched
996// on a subsequent browser start, without requiring any install/upgrade logic
997// to be run, then perform setup for step 3.
998IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
999                       PRE_ComponentAppBackgroundPage) {
1000
1001  // Since the component app is now installed, re-adding it in the same profile
1002  // should not cause it to be re-installed. Instead, we wait for the OnLaunched
1003  // in a different observer (which would timeout if not the app was not
1004  // previously installed properly) and then check this observer to make sure it
1005  // never saw the NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED event.
1006  CheckExtensionInstalledObserver should_not_install;
1007  const Extension* extension = LoadExtensionAsComponent(
1008      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
1009  ASSERT_TRUE(extension);
1010
1011  ExtensionTestMessageListener launched_listener("Launched", false);
1012  OpenApplication(AppLaunchParams(
1013      browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
1014
1015  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1016  ASSERT_FALSE(should_not_install.seen());
1017
1018  // Simulate a "downgrade" from version 2 in the test manifest.json to 1.
1019  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser()->profile());
1020
1021  // Clear the registered events to ensure they are updated.
1022  extensions::EventRouter::Get(browser()->profile())
1023      ->SetRegisteredEvents(extension->id(), std::set<std::string>());
1024
1025  DictionaryPrefUpdate update(extension_prefs->pref_service(),
1026                              extensions::pref_names::kExtensions);
1027  base::DictionaryValue* dict = update.Get();
1028  std::string key(extension->id());
1029  key += ".manifest.version";
1030  dict->SetString(key, "1");
1031}
1032
1033// Component App Test 3 of 3: simulate a component extension upgrade that
1034// re-adds the OnLaunched event, and allows the app to be launched.
1035IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
1036  CheckExtensionInstalledObserver should_install;
1037  // Since we are forcing an upgrade, we need to wait for the load again.
1038  content::WindowedNotificationObserver app_loaded_observer(
1039      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
1040      content::NotificationService::AllSources());
1041
1042  const Extension* extension = LoadExtensionAsComponent(
1043      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
1044  ASSERT_TRUE(extension);
1045  app_loaded_observer.Wait();
1046  ASSERT_TRUE(should_install.seen());
1047
1048  ExtensionTestMessageListener launched_listener("Launched", false);
1049  OpenApplication(AppLaunchParams(
1050      browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
1051
1052  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1053}
1054
1055IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
1056                       ComponentExtensionRuntimeReload) {
1057  // Ensure that we wait until the background page is run (to register the
1058  // OnLaunched listener) before trying to open the application. This is similar
1059  // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
1060  content::WindowedNotificationObserver app_loaded_observer(
1061      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
1062      content::NotificationService::AllSources());
1063
1064  const Extension* extension = LoadExtensionAsComponent(
1065      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
1066  ASSERT_TRUE(extension);
1067
1068  app_loaded_observer.Wait();
1069
1070  {
1071    ExtensionTestMessageListener launched_listener("Launched", false);
1072    OpenApplication(AppLaunchParams(
1073        browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
1074    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1075  }
1076
1077  {
1078    ExtensionTestMessageListener launched_listener("Launched", false);
1079    ASSERT_TRUE(ExecuteScriptInBackgroundPageNoWait(
1080        extension->id(),
1081        // NoWait actually waits for a domAutomationController.send() which is
1082        // implicitly append to the script. Since reload() restarts the
1083        // extension, the send after reload may not get executed. To get around
1084        // this, send first, then execute the reload().
1085        "window.domAutomationController.send(0);"
1086        "chrome.runtime.reload();"));
1087    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
1088  }
1089}
1090
1091// Fails on Win7. http://crbug.com/171450
1092#if defined(OS_WIN)
1093#define MAYBE_Messaging DISABLED_Messaging
1094#else
1095#define MAYBE_Messaging Messaging
1096#endif
1097IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Messaging) {
1098  ResultCatcher result_catcher;
1099  LoadAndLaunchPlatformApp("messaging/app2", "Ready");
1100  LoadAndLaunchPlatformApp("messaging/app1", "Launched");
1101  EXPECT_TRUE(result_catcher.GetNextResult());
1102}
1103
1104// TODO(linux_aura) http://crbug.com/163931
1105#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
1106#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
1107#else
1108// This test depends on focus and so needs to be in interactive_ui_tests.
1109// http://crbug.com/227041
1110#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
1111#endif
1112IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_WebContentsHasFocus) {
1113  LoadAndLaunchPlatformApp("minimal", "Launched");
1114
1115  EXPECT_EQ(1LU, GetAppWindowCount());
1116  EXPECT_TRUE(GetFirstAppWindow()
1117                  ->web_contents()
1118                  ->GetRenderWidgetHostView()
1119                  ->HasFocus());
1120}
1121
1122
1123#if defined(ENABLE_FULL_PRINTING)
1124
1125#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
1126#define MAYBE_WindowDotPrintShouldBringUpPrintPreview \
1127    DISABLED_WindowDotPrintShouldBringUpPrintPreview
1128#else
1129#define MAYBE_WindowDotPrintShouldBringUpPrintPreview \
1130    WindowDotPrintShouldBringUpPrintPreview
1131#endif
1132
1133IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
1134                       MAYBE_WindowDotPrintShouldBringUpPrintPreview) {
1135  ScopedPreviewTestingDelegate preview_delegate(true);
1136  ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
1137  preview_delegate.WaitUntilPreviewIsReady();
1138}
1139
1140// This test verifies that http://crbug.com/297179 is fixed.
1141IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
1142                       DISABLED_ClosingWindowWhilePrintingShouldNotCrash) {
1143  ScopedPreviewTestingDelegate preview_delegate(false);
1144  ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
1145  preview_delegate.WaitUntilPreviewIsReady();
1146  GetFirstAppWindow()->GetBaseWindow()->Close();
1147}
1148
1149// This test currently only passes on OS X (on other platforms the print preview
1150// dialog's size is limited by the size of the window being printed).
1151#if !defined(OS_MACOSX)
1152#define MAYBE_PrintPreviewShouldNotBeTooSmall \
1153    DISABLED_PrintPreviewShouldNotBeTooSmall
1154#else
1155#define MAYBE_PrintPreviewShouldNotBeTooSmall \
1156    PrintPreviewShouldNotBeTooSmall
1157#endif
1158
1159IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
1160                       MAYBE_PrintPreviewShouldNotBeTooSmall) {
1161  // Print preview dialogs with widths less than 410 pixels will have preview
1162  // areas that are too small, and ones with heights less than 191 pixels will
1163  // have vertical scrollers for their controls that are too small.
1164  gfx::Size minimum_dialog_size(410, 191);
1165  ScopedPreviewTestingDelegate preview_delegate(false);
1166  ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
1167  preview_delegate.WaitUntilPreviewIsReady();
1168  EXPECT_GE(preview_delegate.dialog_size().width(),
1169            minimum_dialog_size.width());
1170  EXPECT_GE(preview_delegate.dialog_size().height(),
1171            minimum_dialog_size.height());
1172  GetFirstAppWindow()->GetBaseWindow()->Close();
1173}
1174#endif  // ENABLE_FULL_PRINTING
1175
1176
1177#if defined(OS_CHROMEOS)
1178
1179class PlatformAppIncognitoBrowserTest : public PlatformAppBrowserTest,
1180                                        public AppWindowRegistry::Observer {
1181 public:
1182  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1183    // Tell chromeos to launch in Guest mode, aka incognito.
1184    command_line->AppendSwitch(switches::kIncognito);
1185    PlatformAppBrowserTest::SetUpCommandLine(command_line);
1186  }
1187  virtual void SetUp() OVERRIDE {
1188    // Make sure the file manager actually gets loaded.
1189    ComponentLoader::EnableBackgroundExtensionsForTesting();
1190    PlatformAppBrowserTest::SetUp();
1191  }
1192
1193  // AppWindowRegistry::Observer implementation.
1194  virtual void OnAppWindowAdded(AppWindow* app_window) OVERRIDE {
1195    opener_app_ids_.insert(app_window->extension_id());
1196  }
1197
1198 protected:
1199  // A set of ids of apps we've seen open a app window.
1200  std::set<std::string> opener_app_ids_;
1201};
1202
1203IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
1204  // Get the file manager app.
1205  const Extension* file_manager = extension_service()->GetExtensionById(
1206      "hhaomjibdihmijegdhdafkllkbggdgoj", false);
1207  ASSERT_TRUE(file_manager != NULL);
1208  Profile* incognito_profile = profile()->GetOffTheRecordProfile();
1209  ASSERT_TRUE(incognito_profile != NULL);
1210
1211  // Wait until the file manager has had a chance to register its listener
1212  // for the launch event.
1213  EventRouter* router = EventRouter::Get(incognito_profile);
1214  ASSERT_TRUE(router != NULL);
1215  while (!router->ExtensionHasEventListener(
1216      file_manager->id(), app_runtime::OnLaunched::kEventName)) {
1217    content::RunAllPendingInMessageLoop();
1218  }
1219
1220  // Listen for new app windows so we see the file manager app launch itself.
1221  AppWindowRegistry* registry = AppWindowRegistry::Get(incognito_profile);
1222  ASSERT_TRUE(registry != NULL);
1223  registry->AddObserver(this);
1224
1225  OpenApplication(AppLaunchParams(
1226      incognito_profile, file_manager, 0, chrome::HOST_DESKTOP_TYPE_NATIVE));
1227
1228  while (!ContainsKey(opener_app_ids_, file_manager->id())) {
1229    content::RunAllPendingInMessageLoop();
1230  }
1231}
1232
1233class RestartDeviceTest : public PlatformAppBrowserTest {
1234 public:
1235  RestartDeviceTest()
1236      : power_manager_client_(NULL),
1237        mock_user_manager_(NULL) {}
1238  virtual ~RestartDeviceTest() {}
1239
1240  // PlatformAppBrowserTest overrides
1241  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
1242    PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture();
1243
1244    power_manager_client_ = new chromeos::FakePowerManagerClient;
1245    chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
1246        scoped_ptr<chromeos::PowerManagerClient>(power_manager_client_));
1247  }
1248
1249  virtual void SetUpOnMainThread() OVERRIDE {
1250    PlatformAppBrowserTest::SetUpOnMainThread();
1251
1252    mock_user_manager_ = new chromeos::MockUserManager;
1253    user_manager_enabler_.reset(
1254        new chromeos::ScopedUserManagerEnabler(mock_user_manager_));
1255
1256    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
1257        .WillRepeatedly(testing::Return(true));
1258    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsKioskApp())
1259        .WillRepeatedly(testing::Return(true));
1260  }
1261
1262  virtual void TearDownOnMainThread() OVERRIDE {
1263    user_manager_enabler_.reset();
1264    PlatformAppBrowserTest::TearDownOnMainThread();
1265  }
1266
1267  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
1268    PlatformAppBrowserTest::TearDownInProcessBrowserTestFixture();
1269  }
1270
1271  int num_request_restart_calls() const {
1272    return power_manager_client_->num_request_restart_calls();
1273  }
1274
1275 private:
1276  chromeos::FakePowerManagerClient* power_manager_client_;
1277  chromeos::MockUserManager* mock_user_manager_;
1278  scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
1279
1280  DISALLOW_COPY_AND_ASSIGN(RestartDeviceTest);
1281};
1282
1283// Tests that chrome.runtime.restart would request device restart in
1284// ChromeOS kiosk mode.
1285IN_PROC_BROWSER_TEST_F(RestartDeviceTest, Restart) {
1286  ASSERT_EQ(0, num_request_restart_calls());
1287
1288  ExtensionTestMessageListener launched_listener("Launched", true);
1289  const Extension* extension = LoadAndLaunchPlatformApp("restart_device",
1290                                                        &launched_listener);
1291  ASSERT_TRUE(extension);
1292
1293  launched_listener.Reply("restart");
1294  ExtensionTestMessageListener restart_requested_listener("restartRequested",
1295                                                          false);
1296  ASSERT_TRUE(restart_requested_listener.WaitUntilSatisfied());
1297
1298  EXPECT_EQ(1, num_request_restart_calls());
1299}
1300
1301#endif  // defined(OS_CHROMEOS)
1302
1303// Test that when an application is uninstalled and re-install it does not have
1304// access to the previously set data.
1305IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReinstallDataCleanup) {
1306  // The application is installed and launched. After the 'Launched' message is
1307  // acknowledged by the browser process, the application will test that some
1308  // data are not installed and then install them. The application will then be
1309  // uninstalled and the same process will be repeated.
1310  std::string extension_id;
1311
1312  {
1313    const Extension* extension =
1314        LoadAndLaunchPlatformApp("reinstall_data_cleanup", "Launched");
1315    ASSERT_TRUE(extension);
1316    extension_id = extension->id();
1317
1318    ResultCatcher result_catcher;
1319    EXPECT_TRUE(result_catcher.GetNextResult());
1320  }
1321
1322  UninstallExtension(extension_id);
1323  content::RunAllPendingInMessageLoop();
1324
1325  {
1326    const Extension* extension =
1327        LoadAndLaunchPlatformApp("reinstall_data_cleanup", "Launched");
1328    ASSERT_TRUE(extension);
1329    ASSERT_EQ(extension_id, extension->id());
1330
1331    ResultCatcher result_catcher;
1332    EXPECT_TRUE(result_catcher.GetNextResult());
1333  }
1334}
1335
1336}  // namespace extensions
1337