<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/platform_app_browsertest_util.h"
#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_process_host.h"

using content::WebContents;
using extensions::Extension;

namespace {
// Non-abstract RenderViewContextMenu class.
class PlatformAppContextMenu : public RenderViewContextMenu {
 public:
  PlatformAppContextMenu(WebContents* web_contents,
                         const content::ContextMenuParams& params)
      : RenderViewContextMenu(web_contents, params) {}

  bool HasCommandWithId(int command_id) {
    return menu_model_.GetIndexOfCommandId(command_id) != -1;
  }

 protected:
  // These two functions implement pure virtual methods of
  // RenderViewContextMenu.
  virtual bool GetAcceleratorForCommandId(int command_id,
                                          ui::Accelerator* accelerator) {
    return false;
  }
  virtual void PlatformInit() {}
  virtual void PlatformCancel() {}
};

}  // namespace

// Tests that CreateShellWindow doesn't crash if you close it straight away.
// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
// ash, so we test that it works here.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
  ShellWindow* window = CreateShellWindow(extension);
  CloseShellWindow(window);
}

// Tests that platform apps received the "launch" event when launched.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("minimal");

  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  // The empty app doesn't add any context menu items, so its menu should
  // only include the developer tools.
  WebContents* web_contents = GetFirstShellWindowWebContents();
  ASSERT_TRUE(web_contents);
  WebKit::WebContextMenuData data;
  content::ContextMenuParams params(data);
  PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents,
      params);
  menu->Init();
  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_RELOAD));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("context_menu");

  // Wait for the extension to tell us it's initialized its context menus and
  // launched a window.
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  // The context_menu app has one context menu item. This, along with a
  // separator and the developer tools, is all that should be in the menu.
  WebContents* web_contents = GetFirstShellWindowWebContents();
  ASSERT_TRUE(web_contents);
  WebKit::WebContextMenuData data;
  content::ContextMenuParams params(data);
  PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents,
      params);
  menu->Init();
  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_RELOAD));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
}

// Tests that localStorage and WebSQL are disabled for platform apps.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
}

// Tests that platform apps can use the chrome.appWindow.* API.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApi) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/windows_api")) << message_;
}

// Tests that platform apps have isolated storage by default.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
  ASSERT_TRUE(StartTestServer());

  // Load a (non-app) page under the "localhost" origin that sets a cookie.
  GURL set_cookie_url = test_server()->GetURL(
      "files/extensions/platform_apps/isolation/set_cookie.html");
  GURL::Replacements replace_host;
  std::string host_str("localhost");  // Must stay in scope with replace_host.
  replace_host.SetHostStr(host_str);
  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);

  ui_test_utils::NavigateToURLWithDisposition(
      browser(), set_cookie_url,
      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);

  // Make sure the cookie is set.
  int cookie_size;
  std::string cookie_value;
  automation_util::GetCookies(
      set_cookie_url,
      chrome::GetWebContentsAt(browser(), 0),
      &cookie_size,
      &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  // Let the platform app request the same URL, and make sure that it doesn't
  // see the cookie.
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ExtensionWindowingApis) {
  // Initially there should be just the one browser window visible to the
  // extensions API.
  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("common/background_page"));
  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));

  // And no shell windows.
  ASSERT_EQ(0U, GetShellWindowCount());

  // Launch a platform app that shows a window.
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("minimal");
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
  ASSERT_EQ(1U, GetShellWindowCount());
  ShellWindowRegistry::ShellWindowSet shell_windows =
      ShellWindowRegistry::Get(browser()->profile())->shell_windows();
  int shell_window_id = (*shell_windows.begin())->session_id().id();

  // But it's not visible to the extensions API, it still thinks there's just
  // one browser window.
  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
  // It can't look it up by ID either
  ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));

  // The app can also only see one window (its own).
  // TODO(jeremya): add an extension function to get a shell window by ID, and
  // to get a list of all the shell windows, so we can test this.

  // Launch another platform app that also shows a window.
  ExtensionTestMessageListener launched_listener2("Launched", false);
  LoadAndLaunchPlatformApp("context_menu");
  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());

  // There are two total shell windows, but each app can only see its own.
  ASSERT_EQ(2U, GetShellWindowCount());
  // TODO(jeremya): as above, this requires more extension functions.
}

// TODO(benwells): fix these tests for ChromeOS.
#if !defined(OS_CHROMEOS)
// Tests that command line parameters get passed through to platform apps
// via launchData correctly when launching with a file.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
  SetCommandLineArg( "platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
      << message_;
}

// Tests that no launch data is sent through if the platform app provides
// an intent with the wrong action.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongIntent) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_intent"))
      << message_;
}

// Tests that no launch data is sent through if the file is of the wrong MIME
// type.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
      << message_;
}

// Tests that no launch data is sent through if the platform app does not
// provide an intent.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
      << message_;
}

// Tests that no launch data is sent through if the file MIME type cannot
// be read.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if the file does not exist.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if the argument is a directory.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
  SetCommandLineArg("platform_apps/launch_files");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if there are no arguments passed
// on the command line
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
  ClearCommandLineArgs();
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
      << message_;
}

// Test that platform apps can use the chrome.fileSystem.getDisplayPath
// function to get the native file system path of a file they are launched with.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
      << message_;
}

#endif  // defined(OS_CHROMEOS)

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
  ASSERT_TRUE(StartTestServer());
  ui_test_utils::WindowedNotificationObserver observer(
      chrome::NOTIFICATION_TAB_ADDED,
      content::Source<content::WebContentsDelegate>(browser()));
  LoadAndLaunchPlatformApp("open_link");
  observer.Wait();
  ASSERT_EQ(2, browser()->tab_count());
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, BrowserTag) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/browser_tag")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, BrowserTagIsolation) {
  ASSERT_TRUE(StartTestServer());

  // Load a (non-app) page under the "localhost" origin that sets a cookie.
  GURL set_cookie_url = test_server()->GetURL(
      "files/extensions/platform_apps/isolation/set_cookie.html");
  GURL::Replacements replace_host;
  std::string host_str("localhost");  // Must stay in scope with replace_host.
  replace_host.SetHostStr(host_str);
  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);

  ui_test_utils::NavigateToURLWithDisposition(
      browser(), set_cookie_url,
      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);

  // Make sure the cookie is set.
  int cookie_size;
  std::string cookie_value;
  automation_util::GetCookies(set_cookie_url,
                              chrome::GetWebContentsAt(browser(), 0),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  // Create a listener to JS message to know when the app has launched.
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("browser_tag_isolation");
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  ui_test_utils::WindowedNotificationObserver load_stop_observer(
      content::NOTIFICATION_LOAD_STOP,
      content::NotificationService::AllSources());
  load_stop_observer.Wait();
  content::Source<content::NavigationController> source =
      load_stop_observer.source();

  // Test the regular browser context to ensure we still have only one cookie.
  automation_util::GetCookies(GURL("http://localhost"),
                              chrome::GetWebContentsAt(browser(), 0),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  ASSERT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());

  // Now, test the browser tag to ensure we have properly set the cookie and
  // we have only one.
  automation_util::GetCookies(GURL("http://localhost"),
                              source->GetWebContents(),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("isolation_guest=true", cookie_value);
}
<commit_msg>Disable PlatformAppBrowserTest.BrowserTagIsolation because it crashes on chromiumos<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/platform_app_browsertest_util.h"
#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_process_host.h"

using content::WebContents;
using extensions::Extension;

namespace {
// Non-abstract RenderViewContextMenu class.
class PlatformAppContextMenu : public RenderViewContextMenu {
 public:
  PlatformAppContextMenu(WebContents* web_contents,
                         const content::ContextMenuParams& params)
      : RenderViewContextMenu(web_contents, params) {}

  bool HasCommandWithId(int command_id) {
    return menu_model_.GetIndexOfCommandId(command_id) != -1;
  }

 protected:
  // These two functions implement pure virtual methods of
  // RenderViewContextMenu.
  virtual bool GetAcceleratorForCommandId(int command_id,
                                          ui::Accelerator* accelerator) {
    return false;
  }
  virtual void PlatformInit() {}
  virtual void PlatformCancel() {}
};

}  // namespace

// Tests that CreateShellWindow doesn't crash if you close it straight away.
// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
// ash, so we test that it works here.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
  ShellWindow* window = CreateShellWindow(extension);
  CloseShellWindow(window);
}

// Tests that platform apps received the "launch" event when launched.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("minimal");

  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  // The empty app doesn't add any context menu items, so its menu should
  // only include the developer tools.
  WebContents* web_contents = GetFirstShellWindowWebContents();
  ASSERT_TRUE(web_contents);
  WebKit::WebContextMenuData data;
  content::ContextMenuParams params(data);
  PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents,
      params);
  menu->Init();
  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_RELOAD));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("context_menu");

  // Wait for the extension to tell us it's initialized its context menus and
  // launched a window.
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  // The context_menu app has one context menu item. This, along with a
  // separator and the developer tools, is all that should be in the menu.
  WebContents* web_contents = GetFirstShellWindowWebContents();
  ASSERT_TRUE(web_contents);
  WebKit::WebContextMenuData data;
  content::ContextMenuParams params(data);
  PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents,
      params);
  menu->Init();
  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
  ASSERT_TRUE(menu->HasCommandWithId(IDC_RELOAD));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
}

// Tests that localStorage and WebSQL are disabled for platform apps.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
}

// Tests that platform apps can use the chrome.appWindow.* API.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApi) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/windows_api")) << message_;
}

// Tests that platform apps have isolated storage by default.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
  ASSERT_TRUE(StartTestServer());

  // Load a (non-app) page under the "localhost" origin that sets a cookie.
  GURL set_cookie_url = test_server()->GetURL(
      "files/extensions/platform_apps/isolation/set_cookie.html");
  GURL::Replacements replace_host;
  std::string host_str("localhost");  // Must stay in scope with replace_host.
  replace_host.SetHostStr(host_str);
  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);

  ui_test_utils::NavigateToURLWithDisposition(
      browser(), set_cookie_url,
      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);

  // Make sure the cookie is set.
  int cookie_size;
  std::string cookie_value;
  automation_util::GetCookies(
      set_cookie_url,
      chrome::GetWebContentsAt(browser(), 0),
      &cookie_size,
      &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  // Let the platform app request the same URL, and make sure that it doesn't
  // see the cookie.
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ExtensionWindowingApis) {
  // Initially there should be just the one browser window visible to the
  // extensions API.
  const Extension* extension = LoadExtension(
      test_data_dir_.AppendASCII("common/background_page"));
  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));

  // And no shell windows.
  ASSERT_EQ(0U, GetShellWindowCount());

  // Launch a platform app that shows a window.
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("minimal");
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
  ASSERT_EQ(1U, GetShellWindowCount());
  ShellWindowRegistry::ShellWindowSet shell_windows =
      ShellWindowRegistry::Get(browser()->profile())->shell_windows();
  int shell_window_id = (*shell_windows.begin())->session_id().id();

  // But it's not visible to the extensions API, it still thinks there's just
  // one browser window.
  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
  // It can't look it up by ID either
  ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));

  // The app can also only see one window (its own).
  // TODO(jeremya): add an extension function to get a shell window by ID, and
  // to get a list of all the shell windows, so we can test this.

  // Launch another platform app that also shows a window.
  ExtensionTestMessageListener launched_listener2("Launched", false);
  LoadAndLaunchPlatformApp("context_menu");
  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());

  // There are two total shell windows, but each app can only see its own.
  ASSERT_EQ(2U, GetShellWindowCount());
  // TODO(jeremya): as above, this requires more extension functions.
}

// TODO(benwells): fix these tests for ChromeOS.
#if !defined(OS_CHROMEOS)
// Tests that command line parameters get passed through to platform apps
// via launchData correctly when launching with a file.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
  SetCommandLineArg( "platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
      << message_;
}

// Tests that no launch data is sent through if the platform app provides
// an intent with the wrong action.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongIntent) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_intent"))
      << message_;
}

// Tests that no launch data is sent through if the file is of the wrong MIME
// type.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
      << message_;
}

// Tests that no launch data is sent through if the platform app does not
// provide an intent.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
      << message_;
}

// Tests that no launch data is sent through if the file MIME type cannot
// be read.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if the file does not exist.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if the argument is a directory.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
  SetCommandLineArg("platform_apps/launch_files");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
      << message_;
}

// Tests that no launch data is sent through if there are no arguments passed
// on the command line
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
  ClearCommandLineArgs();
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
      << message_;
}

// Test that platform apps can use the chrome.fileSystem.getDisplayPath
// function to get the native file system path of a file they are launched with.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
  SetCommandLineArg("platform_apps/launch_files/test.txt");
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
      << message_;
}

#endif  // defined(OS_CHROMEOS)

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
  ASSERT_TRUE(StartTestServer());
  ui_test_utils::WindowedNotificationObserver observer(
      chrome::NOTIFICATION_TAB_ADDED,
      content::Source<content::WebContentsDelegate>(browser()));
  LoadAndLaunchPlatformApp("open_link");
  observer.Wait();
  ASSERT_EQ(2, browser()->tab_count());
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, BrowserTag) {
  ASSERT_TRUE(RunPlatformAppTest("platform_apps/browser_tag")) << message_;
}

// This test is disabled. nasko is working on a fix and it should be committed
// within the hour. The test crashed on linux chromiumos.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DISABLED_BrowserTagIsolation) {
  ASSERT_TRUE(StartTestServer());

  // Load a (non-app) page under the "localhost" origin that sets a cookie.
  GURL set_cookie_url = test_server()->GetURL(
      "files/extensions/platform_apps/isolation/set_cookie.html");
  GURL::Replacements replace_host;
  std::string host_str("localhost");  // Must stay in scope with replace_host.
  replace_host.SetHostStr(host_str);
  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);

  ui_test_utils::NavigateToURLWithDisposition(
      browser(), set_cookie_url,
      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);

  // Make sure the cookie is set.
  int cookie_size;
  std::string cookie_value;
  automation_util::GetCookies(set_cookie_url,
                              chrome::GetWebContentsAt(browser(), 0),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  // Create a listener to JS message to know when the app has launched.
  ExtensionTestMessageListener launched_listener("Launched", false);
  LoadAndLaunchPlatformApp("browser_tag_isolation");
  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());

  ui_test_utils::WindowedNotificationObserver load_stop_observer(
      content::NOTIFICATION_LOAD_STOP,
      content::NotificationService::AllSources());
  load_stop_observer.Wait();
  content::Source<content::NavigationController> source =
      load_stop_observer.source();

  // Test the regular browser context to ensure we still have only one cookie.
  automation_util::GetCookies(GURL("http://localhost"),
                              chrome::GetWebContentsAt(browser(), 0),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("testCookie=1", cookie_value);

  ASSERT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());

  // Now, test the browser tag to ensure we have properly set the cookie and
  // we have only one.
  automation_util::GetCookies(GURL("http://localhost"),
                              source->GetWebContents(),
                              &cookie_size, &cookie_value);
  ASSERT_EQ("isolation_guest=true", cookie_value);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prefs/pref_hash_calculator.h"

#include <string>

#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"

TEST(PrefHashCalculatorTest, TestCurrentAlgorithm) {
  base::StringValue string_value_1("string value 1");
  base::StringValue string_value_2("string value 2");
  base::DictionaryValue dictionary_value_1;
  dictionary_value_1.SetInteger("int value", 1);
  dictionary_value_1.Set("nested empty map", new base::DictionaryValue);
  base::DictionaryValue dictionary_value_1_equivalent;
  dictionary_value_1_equivalent.SetInteger("int value", 1);
  base::DictionaryValue dictionary_value_2;
  dictionary_value_2.SetInteger("int value", 2);

  PrefHashCalculator calc1("seed1", "deviceid");
  PrefHashCalculator calc1_dup("seed1", "deviceid");
  PrefHashCalculator calc2("seed2", "deviceid");
  PrefHashCalculator calc3("seed1", "deviceid2");

  // Two calculators with same seed produce same hash.
  ASSERT_EQ(calc1.Calculate("pref_path", &string_value_1),
            calc1_dup.Calculate("pref_path", &string_value_1));
  ASSERT_EQ(PrefHashCalculator::VALID,
            calc1_dup.Validate(
                "pref_path",
                &string_value_1,
                calc1.Calculate("pref_path", &string_value_1)));

  // Different seeds, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc2.Calculate("pref_path", &string_value_1));
  ASSERT_EQ(PrefHashCalculator::INVALID,
            calc2.Validate(
                "pref_path",
                &string_value_1,
                calc1.Calculate("pref_path", &string_value_1)));

  // Different device IDs, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc3.Calculate("pref_path", &string_value_1));

  // Different values, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc1.Calculate("pref_path", &string_value_2));

  // Different paths, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc1.Calculate("pref_path_2", &string_value_1));

  // Works for dictionaries.
  ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_1));
  ASSERT_NE(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_2));

  // Empty dictionary children are pruned.
  ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_1_equivalent));

  // NULL value is supported.
  ASSERT_FALSE(calc1.Calculate("pref_path", NULL).empty());
}

// Tests the output against a known value to catch unexpected algorithm changes.
TEST(PrefHashCalculatorTest, CatchHashChanges) {
  static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
  static const char kDeviceId[] = "test_device_id1";
  {
    static const char kExpectedValue[] =
        "D8137B8E767D3D910DCD3821CAC61D26ABB042E6EC406AEB0E347ED73A3A4EC1";

    base::ListValue list;
    list.Set(0, new base::FundamentalValue(true));
    list.Set(1, new base::FundamentalValue(100));
    list.Set(2, new base::FundamentalValue(1.0));

    EXPECT_EQ(PrefHashCalculator::VALID,
              PrefHashCalculator(kSeed, kDeviceId).Validate(
                  "pref.path2", &list, kExpectedValue));
  }
  {
    static const char kExpectedValue[] =
        "3F947A044DE9E421A735525385B4C789693682E6F6E3E4CB4741E58724B28F96";

    base::DictionaryValue dict;
    dict.Set("a", new base::StringValue("foo"));
    dict.Set("d", new base::StringValue("bad"));
    dict.Set("b", new base::StringValue("bar"));
    dict.Set("c", new base::StringValue("baz"));

    EXPECT_EQ(PrefHashCalculator::VALID,
              PrefHashCalculator(kSeed, kDeviceId).Validate(
                  "pref.path1", &dict, kExpectedValue));
  }
}

TEST(PrefHashCalculatorTest, TestCompatibilityWithPrefMetricsService) {
  static const char kSeed[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
  };
  static const char kDeviceId[] =
      "D730D9CBD98C734A4FB097A1922275FE9F7E026A4EA1BE0E84";
  static const char kExpectedValue[] =
      "845EF34663FF8D32BE6707F40258FBA531C2BFC532E3B014AFB3476115C2A9DE";

  base::ListValue startup_urls;
  startup_urls.Set(0, new base::StringValue("http://www.chromium.org/"));

  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(std::string(kSeed, arraysize(kSeed)), kDeviceId).
            Validate("session.startup_urls", &startup_urls, kExpectedValue));
}

TEST(PrefHashCalculatorTest, TestLegacyAlgorithm) {
  static const char kExpectedValue[] =
      "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2";
  static const char kDeviceId[] = "not_used";

  base::DictionaryValue dict;
  dict.Set("a", new base::StringValue("foo"));
  dict.Set("d", new base::StringValue("bad"));
  dict.Set("b", new base::StringValue("bar"));
  dict.Set("c", new base::StringValue("baz"));

  // 32 NULL bytes is the seed that was used to generate the legacy hash.
  EXPECT_EQ(PrefHashCalculator::VALID_LEGACY,
            PrefHashCalculator(std::string(32u, 0), kDeviceId).Validate(
                "pref.path1", &dict, kExpectedValue));
}
<commit_msg>Ensure no changes to the JSONSerializer or PrefHashCalculator ever end up producing different hashes for all existing Value::Type.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prefs/pref_hash_calculator.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"

TEST(PrefHashCalculatorTest, TestCurrentAlgorithm) {
  base::StringValue string_value_1("string value 1");
  base::StringValue string_value_2("string value 2");
  base::DictionaryValue dictionary_value_1;
  dictionary_value_1.SetInteger("int value", 1);
  dictionary_value_1.Set("nested empty map", new base::DictionaryValue);
  base::DictionaryValue dictionary_value_1_equivalent;
  dictionary_value_1_equivalent.SetInteger("int value", 1);
  base::DictionaryValue dictionary_value_2;
  dictionary_value_2.SetInteger("int value", 2);

  PrefHashCalculator calc1("seed1", "deviceid");
  PrefHashCalculator calc1_dup("seed1", "deviceid");
  PrefHashCalculator calc2("seed2", "deviceid");
  PrefHashCalculator calc3("seed1", "deviceid2");

  // Two calculators with same seed produce same hash.
  ASSERT_EQ(calc1.Calculate("pref_path", &string_value_1),
            calc1_dup.Calculate("pref_path", &string_value_1));
  ASSERT_EQ(PrefHashCalculator::VALID,
            calc1_dup.Validate(
                "pref_path",
                &string_value_1,
                calc1.Calculate("pref_path", &string_value_1)));

  // Different seeds, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc2.Calculate("pref_path", &string_value_1));
  ASSERT_EQ(PrefHashCalculator::INVALID,
            calc2.Validate(
                "pref_path",
                &string_value_1,
                calc1.Calculate("pref_path", &string_value_1)));

  // Different device IDs, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc3.Calculate("pref_path", &string_value_1));

  // Different values, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc1.Calculate("pref_path", &string_value_2));

  // Different paths, different hashes.
  ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
            calc1.Calculate("pref_path_2", &string_value_1));

  // Works for dictionaries.
  ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_1));
  ASSERT_NE(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_2));

  // Empty dictionary children are pruned.
  ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
            calc1.Calculate("pref_path", &dictionary_value_1_equivalent));

  // NULL value is supported.
  ASSERT_FALSE(calc1.Calculate("pref_path", NULL).empty());
}

// Tests the output against a known value to catch unexpected algorithm changes.
// The test hashes below must NEVER be updated, the serialization algorithm used
// must always be able to generate data that will produce these exact hashes.
TEST(PrefHashCalculatorTest, CatchHashChanges) {
  static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
  static const char kDeviceId[] = "test_device_id1";

  scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
  scoped_ptr<base::Value> bool_value(base::Value::CreateBooleanValue(false));
  scoped_ptr<base::Value> int_value(
      base::Value::CreateIntegerValue(1234567890));
  scoped_ptr<base::Value> double_value(
      base::Value::CreateDoubleValue(123.0987654321));
  scoped_ptr<base::Value> string_value(base::Value::CreateStringValue(
      "testing with special chars:\n<>{}:^^@#$\\/"));

  scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue);
  dict_value->Set("a", new base::StringValue("foo"));
  dict_value->Set("d", new base::StringValue("bad"));
  dict_value->Set("b", new base::StringValue("bar"));
  dict_value->Set("c", new base::StringValue("baz"));

  scoped_ptr<base::ListValue> list_value(new base::ListValue);
  list_value->AppendBoolean(true);
  list_value->AppendInteger(100);
  list_value->AppendDouble(1.0);

  ASSERT_EQ(base::Value::TYPE_NULL, null_value->GetType());
  ASSERT_EQ(base::Value::TYPE_BOOLEAN, bool_value->GetType());
  ASSERT_EQ(base::Value::TYPE_INTEGER, int_value->GetType());
  ASSERT_EQ(base::Value::TYPE_DOUBLE, double_value->GetType());
  ASSERT_EQ(base::Value::TYPE_STRING, string_value->GetType());
  ASSERT_EQ(base::Value::TYPE_DICTIONARY, dict_value->GetType());
  ASSERT_EQ(base::Value::TYPE_LIST, list_value->GetType());

  // Test every value type independently. Intentionally omits TYPE_BINARY which
  // isn't even allowed in JSONWriter's input.
  static const char kExpectedNullValue[] =
      "C2871D0AC76176E39948C50A9A562B863E610FDA90C675A6A8AD16B4DC4F53DC";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path", null_value.get(), kExpectedNullValue));

  static const char kExpectedBooleanValue[] =
      "A326E2F405CFE05D08289CDADD9DB4F529592F0945A8CE204289E4C930D8AA43";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path", bool_value.get(), kExpectedBooleanValue));

  static const char kExpectedIntegerValue[] =
      "4B69938F802A2A26D69467F3E1E4A474F6323C64EFC54DBDB4A5708A7D005042";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path", int_value.get(), kExpectedIntegerValue));

  static const char kExpectedDoubleValue[] =
      "1734C9C745B9C92D896B9A710994BF1B56D55BFB0F00C207EC995152AF02F08F";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path", double_value.get(), kExpectedDoubleValue));

  static const char kExpectedStringValue[] =
      "154D15522C856AA944BFA5A9E3FFB46925BF2B95A10199564651CA1C13E98433";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path", string_value.get(), kExpectedStringValue));

  static const char kExpectedDictValue[] =
      "3F947A044DE9E421A735525385B4C789693682E6F6E3E4CB4741E58724B28F96";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path1", dict_value.get(), kExpectedDictValue));

  static const char kExpectedListValue[] =
      "D8137B8E767D3D910DCD3821CAC61D26ABB042E6EC406AEB0E347ED73A3A4EC1";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path2", list_value.get(), kExpectedListValue));

  // Also test every value type together in the same dictionary.
  base::DictionaryValue everything;
  everything.Set("null", null_value.release());
  everything.Set("bool", bool_value.release());
  everything.Set("int", int_value.release());
  everything.Set("double", double_value.release());
  everything.Set("string", string_value.release());
  everything.Set("list", list_value.release());
  everything.Set("dict", dict_value.release());
  static const char kExpectedEverythingValue[] =
      "0A546480C7AB7699779B2FCFA326D65E0AE1446EA62398AE1D338119C6913943";
  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(kSeed, kDeviceId).Validate(
                "pref.path1", &everything, kExpectedEverythingValue));
}

TEST(PrefHashCalculatorTest, TestCompatibilityWithPrefMetricsService) {
  static const char kSeed[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
  };
  static const char kDeviceId[] =
      "D730D9CBD98C734A4FB097A1922275FE9F7E026A4EA1BE0E84";
  static const char kExpectedValue[] =
      "845EF34663FF8D32BE6707F40258FBA531C2BFC532E3B014AFB3476115C2A9DE";

  base::ListValue startup_urls;
  startup_urls.Set(0, new base::StringValue("http://www.chromium.org/"));

  EXPECT_EQ(PrefHashCalculator::VALID,
            PrefHashCalculator(std::string(kSeed, arraysize(kSeed)), kDeviceId).
            Validate("session.startup_urls", &startup_urls, kExpectedValue));
}

TEST(PrefHashCalculatorTest, TestLegacyAlgorithm) {
  static const char kExpectedValue[] =
      "C503FB7C65EEFD5C07185F616A0AA67923C069909933F362022B1F187E73E9A2";
  static const char kDeviceId[] = "not_used";

  base::DictionaryValue dict;
  dict.Set("a", new base::StringValue("foo"));
  dict.Set("d", new base::StringValue("bad"));
  dict.Set("b", new base::StringValue("bar"));
  dict.Set("c", new base::StringValue("baz"));

  // 32 NULL bytes is the seed that was used to generate the legacy hash.
  EXPECT_EQ(PrefHashCalculator::VALID_LEGACY,
            PrefHashCalculator(std::string(32u, 0), kDeviceId).Validate(
                "pref.path1", &dict, kExpectedValue));
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

// Unit tests for SessionStartupPref.
class SessionStartupPrefTest : public testing::Test {
 public:
  virtual void SetUp() {
    pref_service_.reset(new TestingPrefService);
    SessionStartupPref::RegisterUserPrefs(pref_service_.get());
    pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
  }

  scoped_ptr<TestingPrefService> pref_service_;
};

TEST_F(SessionStartupPrefTest, URLListIsFixedUp) {
  ListValue* url_pref_list = new ListValue;
  url_pref_list->Set(0, Value::CreateStringValue("google.com"));
  url_pref_list->Set(1, Value::CreateStringValue("chromium.org"));
  pref_service_->SetUserPref(prefs::kURLsToRestoreOnStartup, url_pref_list);

  SessionStartupPref result =
      SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(2u, result.urls.size());
  EXPECT_EQ("http://google.com/", result.urls[0].spec());
  EXPECT_EQ("http://chromium.org/", result.urls[1].spec());
}

TEST_F(SessionStartupPrefTest, URLListManagedOverridesUser) {
  ListValue* url_pref_list1 = new ListValue;
  url_pref_list1->Set(0, Value::CreateStringValue("chromium.org"));
  pref_service_->SetUserPref(prefs::kURLsToRestoreOnStartup, url_pref_list1);

  ListValue* url_pref_list2 = new ListValue;
  url_pref_list2->Set(0, Value::CreateStringValue("chromium.org"));
  url_pref_list2->Set(1, Value::CreateStringValue("chromium.org"));
  url_pref_list2->Set(2, Value::CreateStringValue("chromium.org"));
  pref_service_->SetManagedPref(prefs::kURLsToRestoreOnStartup,
                                url_pref_list2);

  SessionStartupPref result =
      SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(3u, result.urls.size());

  SessionStartupPref override_test =
      SessionStartupPref(SessionStartupPref::URLS);
  override_test.urls.push_back(GURL("dev.chromium.org"));
  SessionStartupPref::SetStartupPref(pref_service_.get(), override_test);

  result = SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(3u, result.urls.size());
}

// Checks to make sure that if the user had previously not selected anything
// (so that, in effect, the default value "Open the homepage" was selected),
// their preferences are migrated on upgrade to m19.
TEST_F(SessionStartupPrefTest, DefaultMigration) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);

  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

#if defined(OS_CHROMEOS)
  // On ChromeOS, the default is LAST, so no migration should happen.
  EXPECT_EQ(SessionStartupPref::LAST, pref.type);
  EXPECT_EQ(0U, pref.urls.size());
#else
  EXPECT_EQ(SessionStartupPref::URLS, pref.type);
  EXPECT_EQ(1U, pref.urls.size());
  EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
#endif
}

// Checks to make sure that if the user had previously not selected anything
// (so that, in effect, the default value "Open the homepage" was selected),
// and the NTP is being used for the homepage, their preferences are migrated
// to "Open the New Tab Page" on upgrade to M19.
TEST_F(SessionStartupPrefTest, DefaultMigrationHomepageIsNTP) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);

  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

#if defined(OS_CHROMEOS)
  // On ChromeOS, the default is LAST, so no migration should happen.
  EXPECT_EQ(SessionStartupPref::LAST, pref.type);
#else
  EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);
#endif

  // The "URLs to restore on startup" shouldn't get migrated.
  EXPECT_EQ(0U, pref.urls.size());
}

// Checks to make sure that if the user had previously selected "Open the
// "homepage", their preferences are migrated on upgrade to M19.
TEST_F(SessionStartupPrefTest, HomePageMigration) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");

  // By design, it's impossible to set the 'restore on startup' pref to 0
  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
  // using the pref service directly.
  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  EXPECT_EQ(SessionStartupPref::URLS, pref.type);
  EXPECT_EQ(1U, pref.urls.size());
  EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
}

// Checks to make sure that if the user had previously selected "Open the
// "homepage", and the NTP is being used for the homepage, their preferences
// are migrated on upgrade to M19.
TEST_F(SessionStartupPrefTest, HomePageMigrationHomepageIsNTP) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");

  // By design, it's impossible to set the 'restore on startup' pref to 0
  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
  // using the pref service directly.
  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);
}
<commit_msg>[Mac] Fix a crash in SessionStartupPrefTest on 10.7.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(OS_MACOSX)
#include "chrome/browser/ui/cocoa/window_restore_utils.h"
#endif

// Unit tests for SessionStartupPref.
class SessionStartupPrefTest : public testing::Test {
 public:
  virtual void SetUp() {
    pref_service_.reset(new TestingPrefService);
    SessionStartupPref::RegisterUserPrefs(pref_service_.get());
    pref_service_->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
  }

  bool IsUseLastOpenDefault() {
    // On ChromeOS and OS X 10.7+, the default SessionStartupPref is LAST.
#if defined(OS_CHROMEOS)
    return true;
#elif defined(OS_MACOSX)
    return restore_utils::IsWindowRestoreEnabled();
#else
    return false;
#endif
  }

  scoped_ptr<TestingPrefService> pref_service_;
};

TEST_F(SessionStartupPrefTest, URLListIsFixedUp) {
  ListValue* url_pref_list = new ListValue;
  url_pref_list->Set(0, Value::CreateStringValue("google.com"));
  url_pref_list->Set(1, Value::CreateStringValue("chromium.org"));
  pref_service_->SetUserPref(prefs::kURLsToRestoreOnStartup, url_pref_list);

  SessionStartupPref result =
      SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(2u, result.urls.size());
  EXPECT_EQ("http://google.com/", result.urls[0].spec());
  EXPECT_EQ("http://chromium.org/", result.urls[1].spec());
}

TEST_F(SessionStartupPrefTest, URLListManagedOverridesUser) {
  ListValue* url_pref_list1 = new ListValue;
  url_pref_list1->Set(0, Value::CreateStringValue("chromium.org"));
  pref_service_->SetUserPref(prefs::kURLsToRestoreOnStartup, url_pref_list1);

  ListValue* url_pref_list2 = new ListValue;
  url_pref_list2->Set(0, Value::CreateStringValue("chromium.org"));
  url_pref_list2->Set(1, Value::CreateStringValue("chromium.org"));
  url_pref_list2->Set(2, Value::CreateStringValue("chromium.org"));
  pref_service_->SetManagedPref(prefs::kURLsToRestoreOnStartup,
                                url_pref_list2);

  SessionStartupPref result =
      SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(3u, result.urls.size());

  SessionStartupPref override_test =
      SessionStartupPref(SessionStartupPref::URLS);
  override_test.urls.push_back(GURL("dev.chromium.org"));
  SessionStartupPref::SetStartupPref(pref_service_.get(), override_test);

  result = SessionStartupPref::GetStartupPref(pref_service_.get());
  EXPECT_EQ(3u, result.urls.size());
}

// Checks to make sure that if the user had previously not selected anything
// (so that, in effect, the default value "Open the homepage" was selected),
// their preferences are migrated on upgrade to m19.
TEST_F(SessionStartupPrefTest, DefaultMigration) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);

  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  if (IsUseLastOpenDefault()) {
    EXPECT_EQ(SessionStartupPref::LAST, pref.type);
    EXPECT_EQ(0U, pref.urls.size());
  } else {
    EXPECT_EQ(SessionStartupPref::URLS, pref.type);
    EXPECT_EQ(1U, pref.urls.size());
    EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
  }
}

// Checks to make sure that if the user had previously not selected anything
// (so that, in effect, the default value "Open the homepage" was selected),
// and the NTP is being used for the homepage, their preferences are migrated
// to "Open the New Tab Page" on upgrade to M19.
TEST_F(SessionStartupPrefTest, DefaultMigrationHomepageIsNTP) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);

  EXPECT_FALSE(pref_service_->HasPrefPath(prefs::kRestoreOnStartup));

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  if (IsUseLastOpenDefault())
    EXPECT_EQ(SessionStartupPref::LAST, pref.type);
  else
    EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);

  // The "URLs to restore on startup" shouldn't get migrated.
  EXPECT_EQ(0U, pref.urls.size());
}

// Checks to make sure that if the user had previously selected "Open the
// "homepage", their preferences are migrated on upgrade to M19.
TEST_F(SessionStartupPrefTest, HomePageMigration) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");

  // By design, it's impossible to set the 'restore on startup' pref to 0
  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
  // using the pref service directly.
  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, false);

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  EXPECT_EQ(SessionStartupPref::URLS, pref.type);
  EXPECT_EQ(1U, pref.urls.size());
  EXPECT_EQ(GURL("http://chromium.org/"), pref.urls[0]);
}

// Checks to make sure that if the user had previously selected "Open the
// "homepage", and the NTP is being used for the homepage, their preferences
// are migrated on upgrade to M19.
TEST_F(SessionStartupPrefTest, HomePageMigrationHomepageIsNTP) {
  pref_service_->RegisterStringPref(prefs::kHomePage, "http://google.com/");

  // By design, it's impossible to set the 'restore on startup' pref to 0
  // ("open the homepage") using SessionStartupPref::SetStartupPref(), so set it
  // using the pref service directly.
  pref_service_->SetInteger(prefs::kRestoreOnStartup, /*kPrefValueHomePage*/ 0);
  pref_service_->SetString(prefs::kHomePage, "http://chromium.org/");
  pref_service_->SetBoolean(prefs::kHomePageIsNewTabPage, true);

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(
      pref_service_.get());

  EXPECT_EQ(SessionStartupPref::DEFAULT, pref.type);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/extensions/extension_popup.h"

#include "base/bind.h"
#include "base/message_loop.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/insets.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"

#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/views/corewm/window_animations.h"
#endif

using content::RenderViewHost;
using content::WebContents;

namespace {

// Returns true if |possible_parent| is a parent window of |child|.
bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) {
  if (!child)
    return false;
#if !defined(USE_AURA) && defined(OS_WIN)
  if (::GetWindow(child, GW_OWNER) == possible_parent)
    return true;
#endif
  gfx::NativeView parent = child;
  while ((parent = platform_util::GetParent(parent))) {
    if (possible_parent == parent)
      return true;
  }

  return false;
}

}  // namespace

// The minimum/maximum dimensions of the popup.
// The minimum is just a little larger than the size of the button itself.
// The maximum is an arbitrary number that should be smaller than most screens.
const int ExtensionPopup::kMinWidth = 25;
const int ExtensionPopup::kMinHeight = 25;
const int ExtensionPopup::kMaxWidth = 800;
const int ExtensionPopup::kMaxHeight = 600;

ExtensionPopup::ExtensionPopup(
    Browser* browser,
    extensions::ExtensionHost* host,
    views::View* anchor_view,
    views::BubbleBorder::ArrowLocation arrow_location,
    ShowAction show_action)
    : BubbleDelegateView(anchor_view, arrow_location),
      extension_host_(host),
      close_bubble_factory_(this) {
  inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
  // Adjust the margin so that contents fit better.
  const int margin = views::BubbleBorder::GetCornerRadius() / 2;
  set_margins(gfx::Insets(margin, margin, margin, margin));
  SetLayoutManager(new views::FillLayout());
  AddChildView(host->view());
  host->view()->SetContainer(this);
  // Use OnNativeFocusChange to check for child window activation on deactivate.
  set_close_on_deactivate(false);
  // Make the bubble move with its anchor (during inspection, etc.).
  set_move_with_anchor(true);

  // Wait to show the popup until the contained host finishes loading.
  registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
                 content::Source<WebContents>(host->host_contents()));

  // Listen for the containing view calling window.close();
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
                 content::Source<Profile>(host->profile()));

  // Listen for the dev tools opening on this popup, so we can stop it going
  // away when the dev tools get focus.
  registrar_.Add(this, content::NOTIFICATION_DEVTOOLS_AGENT_ATTACHED,
                 content::Source<Profile>(host->profile()));

  // Listen for the dev tools closing, so we can close this window if it is
  // being inspected and the inspector is closed.
  registrar_.Add(this, content::NOTIFICATION_DEVTOOLS_AGENT_DETACHED,
      content::Source<content::BrowserContext>(host->profile()));
}

ExtensionPopup::~ExtensionPopup() {
  views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
}

void ExtensionPopup::Observe(int type,
                             const content::NotificationSource& source,
                             const content::NotificationDetails& details) {
  switch (type) {
    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
      DCHECK(content::Source<WebContents>(host()->host_contents()) == source);
      // Show when the content finishes loading and its width is computed.
      ShowBubble();
      break;
    case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
      // If we aren't the host of the popup, then disregard the notification.
      if (content::Details<extensions::ExtensionHost>(host()) == details)
        GetWidget()->Close();
      break;
    case content::NOTIFICATION_DEVTOOLS_AGENT_DETACHED:
      // Make sure it's the devtools window that inspecting our popup.
      // Widget::Close posts a task, which should give the devtools window a
      // chance to finish detaching from the inspected RenderViewHost.
      if (content::Details<RenderViewHost>(host()->render_view_host()) ==
          details) {
        GetWidget()->Close();
      }
      break;
    case content::NOTIFICATION_DEVTOOLS_AGENT_ATTACHED:
      // First check that the devtools are being opened on this popup.
      if (content::Details<RenderViewHost>(host()->render_view_host()) ==
          details) {
        // Set inspect_with_devtools_ so the popup will be kept open while
        // the devtools are open.
        inspect_with_devtools_ = true;
      }
      break;
    default:
      NOTREACHED() << L"Received unexpected notification";
  }
}

void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
  SizeToContents();
}

gfx::Size ExtensionPopup::GetPreferredSize() {
  // Constrain the size to popup min/max.
  gfx::Size sz = views::View::GetPreferredSize();
  sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
  sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
  return sz;
}

void ExtensionPopup::OnNativeFocusChange(gfx::NativeView focused_before,
                                         gfx::NativeView focused_now) {
  // Don't close if a child of this window is activated (only needed on Win).
  // ExtensionPopups can create Javascipt dialogs; see crbug.com/106723.
  gfx::NativeView this_window = GetWidget()->GetNativeView();
  if (inspect_with_devtools_ || focused_now == this_window ||
      IsParent(focused_now, this_window))
    return;
  // Delay closing the widget because on Aura, closing right away makes the
  // activation controller trigger another focus change before the current focus
  // change is complete.
  if (!close_bubble_factory_.HasWeakPtrs()) {
    MessageLoop::current()->PostTask(FROM_HERE,
        base::Bind(&ExtensionPopup::CloseBubble,
                   close_bubble_factory_.GetWeakPtr()));
  }
}

// static
ExtensionPopup* ExtensionPopup::ShowPopup(
    const GURL& url,
    Browser* browser,
    views::View* anchor_view,
    views::BubbleBorder::ArrowLocation arrow_location,
    ShowAction show_action) {
  ExtensionProcessManager* manager =
      extensions::ExtensionSystem::Get(browser->profile())->process_manager();
  extensions::ExtensionHost* host = manager->CreatePopupHost(url, browser);
  ExtensionPopup* popup = new ExtensionPopup(browser, host, anchor_view,
      arrow_location, show_action);
  views::BubbleDelegateView::CreateBubble(popup);

#if defined(USE_AURA)
  gfx::NativeView native_view = popup->GetWidget()->GetNativeView();
  views::corewm::SetWindowVisibilityAnimationType(
      native_view,
      views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
  views::corewm::SetWindowVisibilityAnimationVerticalPosition(
      native_view,
      -3.0f);
#endif

  // If the host had somehow finished loading, then we'd miss the notification
  // and not show.  This seems to happen in single-process mode.
  if (host->did_stop_loading())
    popup->ShowBubble();

  return popup;
}

void ExtensionPopup::ShowBubble() {
  Show();

  // Focus on the host contents when the bubble is first shown.
  host()->host_contents()->Focus();

  // Listen for widget focus changes after showing (used for non-aura win).
  views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);

  if (inspect_with_devtools_) {
    DevToolsWindow::ToggleDevToolsWindow(host()->render_view_host(),
        true,
        DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
  }
}

void ExtensionPopup::CloseBubble() {
  GetWidget()->Close();
}
<commit_msg>Fix bug where extension popups would not properly receive input focus when first shown.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/extensions/extension_popup.h"

#include "base/bind.h"
#include "base/message_loop.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/insets.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/widget.h"

#if defined(USE_AURA)
#include "ui/aura/window.h"
#include "ui/views/corewm/window_animations.h"
#endif

using content::RenderViewHost;
using content::WebContents;

namespace {

// Returns true if |possible_parent| is a parent window of |child|.
bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) {
  if (!child)
    return false;
#if !defined(USE_AURA) && defined(OS_WIN)
  if (::GetWindow(child, GW_OWNER) == possible_parent)
    return true;
#endif
  gfx::NativeView parent = child;
  while ((parent = platform_util::GetParent(parent))) {
    if (possible_parent == parent)
      return true;
  }

  return false;
}

}  // namespace

// The minimum/maximum dimensions of the popup.
// The minimum is just a little larger than the size of the button itself.
// The maximum is an arbitrary number that should be smaller than most screens.
const int ExtensionPopup::kMinWidth = 25;
const int ExtensionPopup::kMinHeight = 25;
const int ExtensionPopup::kMaxWidth = 800;
const int ExtensionPopup::kMaxHeight = 600;

ExtensionPopup::ExtensionPopup(
    Browser* browser,
    extensions::ExtensionHost* host,
    views::View* anchor_view,
    views::BubbleBorder::ArrowLocation arrow_location,
    ShowAction show_action)
    : BubbleDelegateView(anchor_view, arrow_location),
      extension_host_(host),
      close_bubble_factory_(this) {
  inspect_with_devtools_ = show_action == SHOW_AND_INSPECT;
  // Adjust the margin so that contents fit better.
  const int margin = views::BubbleBorder::GetCornerRadius() / 2;
  set_margins(gfx::Insets(margin, margin, margin, margin));
  SetLayoutManager(new views::FillLayout());
  AddChildView(host->view());
  host->view()->SetContainer(this);
  // Use OnNativeFocusChange to check for child window activation on deactivate.
  set_close_on_deactivate(false);
  // Make the bubble move with its anchor (during inspection, etc.).
  set_move_with_anchor(true);

  // Wait to show the popup until the contained host finishes loading.
  registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
                 content::Source<WebContents>(host->host_contents()));

  // Listen for the containing view calling window.close();
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
                 content::Source<Profile>(host->profile()));

  // Listen for the dev tools opening on this popup, so we can stop it going
  // away when the dev tools get focus.
  registrar_.Add(this, content::NOTIFICATION_DEVTOOLS_AGENT_ATTACHED,
                 content::Source<Profile>(host->profile()));

  // Listen for the dev tools closing, so we can close this window if it is
  // being inspected and the inspector is closed.
  registrar_.Add(this, content::NOTIFICATION_DEVTOOLS_AGENT_DETACHED,
      content::Source<content::BrowserContext>(host->profile()));
}

ExtensionPopup::~ExtensionPopup() {
  views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
}

void ExtensionPopup::Observe(int type,
                             const content::NotificationSource& source,
                             const content::NotificationDetails& details) {
  switch (type) {
    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
      DCHECK(content::Source<WebContents>(host()->host_contents()) == source);
      // Show when the content finishes loading and its width is computed.
      ShowBubble();
      break;
    case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
      // If we aren't the host of the popup, then disregard the notification.
      if (content::Details<extensions::ExtensionHost>(host()) == details)
        GetWidget()->Close();
      break;
    case content::NOTIFICATION_DEVTOOLS_AGENT_DETACHED:
      // Make sure it's the devtools window that inspecting our popup.
      // Widget::Close posts a task, which should give the devtools window a
      // chance to finish detaching from the inspected RenderViewHost.
      if (content::Details<RenderViewHost>(host()->render_view_host()) ==
          details) {
        GetWidget()->Close();
      }
      break;
    case content::NOTIFICATION_DEVTOOLS_AGENT_ATTACHED:
      // First check that the devtools are being opened on this popup.
      if (content::Details<RenderViewHost>(host()->render_view_host()) ==
          details) {
        // Set inspect_with_devtools_ so the popup will be kept open while
        // the devtools are open.
        inspect_with_devtools_ = true;
      }
      break;
    default:
      NOTREACHED() << L"Received unexpected notification";
  }
}

void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
  SizeToContents();
}

gfx::Size ExtensionPopup::GetPreferredSize() {
  // Constrain the size to popup min/max.
  gfx::Size sz = views::View::GetPreferredSize();
  sz.set_width(std::max(kMinWidth, std::min(kMaxWidth, sz.width())));
  sz.set_height(std::max(kMinHeight, std::min(kMaxHeight, sz.height())));
  return sz;
}

void ExtensionPopup::OnNativeFocusChange(gfx::NativeView focused_before,
                                         gfx::NativeView focused_now) {
  // Don't close if a child of this window is activated (only needed on Win).
  // ExtensionPopups can create Javascipt dialogs; see crbug.com/106723.
  gfx::NativeView this_window = GetWidget()->GetNativeView();
  if (inspect_with_devtools_ || focused_now == this_window ||
      IsParent(focused_now, this_window))
    return;
  // Delay closing the widget because on Aura, closing right away makes the
  // activation controller trigger another focus change before the current focus
  // change is complete.
  if (!close_bubble_factory_.HasWeakPtrs()) {
    MessageLoop::current()->PostTask(FROM_HERE,
        base::Bind(&ExtensionPopup::CloseBubble,
                   close_bubble_factory_.GetWeakPtr()));
  }
}

// static
ExtensionPopup* ExtensionPopup::ShowPopup(
    const GURL& url,
    Browser* browser,
    views::View* anchor_view,
    views::BubbleBorder::ArrowLocation arrow_location,
    ShowAction show_action) {
  ExtensionProcessManager* manager =
      extensions::ExtensionSystem::Get(browser->profile())->process_manager();
  extensions::ExtensionHost* host = manager->CreatePopupHost(url, browser);
  ExtensionPopup* popup = new ExtensionPopup(browser, host, anchor_view,
      arrow_location, show_action);
  views::BubbleDelegateView::CreateBubble(popup);

#if defined(USE_AURA)
  gfx::NativeView native_view = popup->GetWidget()->GetNativeView();
  views::corewm::SetWindowVisibilityAnimationType(
      native_view,
      views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
  views::corewm::SetWindowVisibilityAnimationVerticalPosition(
      native_view,
      -3.0f);
#endif

  // If the host had somehow finished loading, then we'd miss the notification
  // and not show.  This seems to happen in single-process mode.
  if (host->did_stop_loading())
    popup->ShowBubble();

  return popup;
}

void ExtensionPopup::ShowBubble() {
  Show();

  // Request focus for the View. Without this, the FocusManager gets confused.
  host()->view()->SetVisible(true);
  host()->view()->RequestFocus();

  // Focus on the host contents when the bubble is first shown.
  host()->host_contents()->Focus();

  // Listen for widget focus changes after showing (used for non-aura win).
  views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);

  if (inspect_with_devtools_) {
    DevToolsWindow::ToggleDevToolsWindow(host()->render_view_host(),
        true,
        DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
  }
}

void ExtensionPopup::CloseBubble() {
  GetWidget()->Close();
}
<|endoftext|>


<commit_before>/*
 * APSP.cpp
 *
 *  Created on: 07.07.2015
 *      Author: Arie Slobbe
 */

#include "APSP.h"
#include "../auxiliary/Log.h"
#include "Dijkstra.h"

namespace NetworKit {

APSP::APSP(const Graph& G) : Algorithm(), G(G) {}

void APSP::run() {
	std::vector<edgeweight> distanceVector(G.upperNodeIdBound(), 0.0);
	distances.resize(G.upperNodeIdBound(), distanceVector);
	G.parallelForNodes([&](node u){
		Dijkstra dijk(G, u);
		dijk.run();
		distances[u] = dijk.getDistances();
	});
	hasRun = true;
}

std::string NetworKit::APSP::toString() const {
	return "All-Pairs Shortest Path Algorithm";
}

} /* namespace NetworKit */
<commit_msg>modified apsp to use bfs when the graph is unweighted<commit_after>/*
 * APSP.cpp
 *
 *  Created on: 07.07.2015
 *      Author: Arie Slobbe
 */

#include "APSP.h"
#include "../auxiliary/Log.h"
#include "Dijkstra.h"
#include "BFS.h"

namespace NetworKit {

APSP::APSP(const Graph& G) : Algorithm(), G(G) {}

void APSP::run() {
	std::vector<edgeweight> distanceVector(G.upperNodeIdBound(), 0.0);
	distances.resize(G.upperNodeIdBound(), distanceVector);
	if (G.isWeighted()) {
		G.parallelForNodes([&](node u){
			Dijkstra dijk(G, u);
			dijk.run();
			distances[u] = dijk.getDistances();
		});
	} else {
		G.parallelForNodes([&](node u){
			BFS bfs(G, u);
			bfs.run();
			distances[u] = bfs.getDistances();
		});
	}
	hasRun = true;
}

std::string NetworKit::APSP::toString() const {
	return "All-Pairs Shortest Path Algorithm";
}

} /* namespace NetworKit */
<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_TIME_HIGHRESOLUTIONCLOCK_HPP
#define CATS_CORECAT_TIME_HIGHRESOLUTIONCLOCK_HPP

#include <chrono>

#include "../Win32/Windows.hpp"

namespace Cats {
namespace Corecat {
namespace Time {

struct HighResolutionClock {

    using rep = double;
    using period = std::ratio<1>;
    using duration = std::chrono::duration<rep, period>;
    using time_point = std::chrono::time_point<BenchmarkClock>;

    static constexpr bool is_steady = false;

    static time_point now() noexcept {

        LARGE_INTEGER nf, n;
        QueryPerformanceFrequency(&nf);
        QueryPerformanceCounter(&n);
        return time_point(duration(double(n.QuadPart) / nf.QuadPart));

    }

};

}
}
}

#endif
<commit_msg>Update HighResolutionClock<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_TIME_HIGHRESOLUTIONCLOCK_HPP
#define CATS_CORECAT_TIME_HIGHRESOLUTIONCLOCK_HPP

#include <chrono>

#include "../Win32/Windows.hpp"

namespace Cats {
namespace Corecat {
namespace Time {

struct HighResolutionClock {

    using rep = double;
    using period = std::ratio<1>;
    using duration = std::chrono::duration<rep, period>;
    using time_point = std::chrono::time_point<HighResolutionClock>;

    static constexpr bool is_steady = false;

    static time_point now() noexcept {

        LARGE_INTEGER nf, n;
        QueryPerformanceFrequency(&nf);
        QueryPerformanceCounter(&n);
        return time_point(duration(double(n.QuadPart) / nf.QuadPart));

    }

};

}
}
}

#endif
<|endoftext|>


<commit_before>#include "ostree.h"
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include "logger.h"

#include <gio/gio.h>

OstreeSysroot *Ostree::LoadSysroot(const std::string &path) {
  OstreeSysroot *sysroot = NULL;

  if (path.size()) {
    sysroot = ostree_sysroot_new(g_file_new_for_path(path.c_str()));
  } else {
    sysroot = ostree_sysroot_new_default();
  }
  GCancellable *cancellable = NULL;
  GError **error = NULL;
  if (!ostree_sysroot_load(sysroot, cancellable, error)) throw std::runtime_error("could not load sysroot");
  return sysroot;
}

OstreeDeployment *Ostree::getBootedDeployment(const std::string &path) {
  OstreeSysroot *sysroot = Ostree::LoadSysroot(path);
  OstreeRepo *repo = NULL;
  OstreeDeployment *booted_deployment = NULL;

  GCancellable *cancellable = NULL;
  GError **error = NULL;

  if (!ostree_sysroot_get_repo(sysroot, &repo, cancellable, error)) throw std::runtime_error("could not get repo");

  booted_deployment = ostree_sysroot_get_booted_deployment(sysroot);
  // booted_deployment = (OstreeDeployment *)ostree_sysroot_get_deployments(sysroot)->pdata[0];
  return booted_deployment;
}

bool Ostree::addRemote(OstreeRepo *repo, const std::string &remote, const std::string &url,
                       const data::PackageManagerCredentials &cred) {
  GCancellable *cancellable = NULL;
  GError *error = NULL;
  GVariantBuilder b;
  GVariant *options;

  g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
  g_variant_builder_add(&b, "{s@v}", "gpg-verify", g_variant_new_variant(g_variant_new_boolean(FALSE)));

  if (cred.cert_file.size() && cred.pkey_file.size() && cred.ca_file.size()) {
    g_variant_builder_add(&b, "{s@v}", "tls-client-cert-path",
                          g_variant_new_variant(g_variant_new_string(cred.cert_file.c_str())));
    g_variant_builder_add(&b, "{s@v}", "tls-client-key-path",
                          g_variant_new_variant(g_variant_new_string(cred.pkey_file.c_str())));
    g_variant_builder_add(&b, "{s@v}", "tls-ca-path",
                          g_variant_new_variant(g_variant_new_string(cred.ca_file.c_str())));
  }
  options = g_variant_builder_end(&b);

  if (!ostree_repo_remote_change(repo, NULL, OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS, remote.c_str(), url.c_str(),
                                 options, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of adding remote: " << error->message);
    return false;
  }
  if (!ostree_repo_remote_change(repo, NULL, OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS, remote.c_str(), url.c_str(),
                                 options, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of adding remote: " << error->message);
    return false;
  }
  return true;
}

#include "ostree-1/ostree.h"

OstreePackage::OstreePackage(const std::string &ecu_serial_in, const std::string &ref_name_in,
                             const std::string &commit_in, const std::string &desc_in, const std::string &treehub_in)
    : ecu_serial(ecu_serial_in), ref_name(ref_name_in), commit(boost::algorithm::to_lower_copy(commit_in)), description(desc_in), pull_uri(treehub_in) {}

data::InstallOutcome OstreePackage::install(const data::PackageManagerCredentials &cred, OstreeConfig config) {
  const char remote[] = "aktualizr-remote";
  const char *const refs[] = {commit.c_str()};
  const char *opt_osname = NULL;
  OstreeRepo *repo = NULL;
  GCancellable *cancellable = NULL;
  GError *error = NULL;
  char *revision;
  GVariantBuilder builder;
  GVariant *options;

  if (config.os.size()) {
    opt_osname = config.os.c_str();
  }
  OstreeSysroot *sysroot = Ostree::LoadSysroot(config.sysroot);
  if (!ostree_sysroot_get_repo(sysroot, &repo, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "could not get repo");
    return data::InstallOutcome(data::INSTALL_FAILED, "could not get repo");
  }

  if (!Ostree::addRemote(repo, remote, pull_uri, cred)) {
    return data::InstallOutcome(data::INSTALL_FAILED, "Error of adding remote");
  }

  g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
  g_variant_builder_add(&builder, "{s@v}", "flags", g_variant_new_variant(g_variant_new_int32(0)));

  g_variant_builder_add(&builder, "{s@v}", "refs", g_variant_new_variant(g_variant_new_strv(refs, 1)));

  if (cred.access_token.size()) {
    GVariantBuilder hdr_builder;
    std::string av("Bearer ");
    av += cred.access_token;
    g_variant_builder_init(&hdr_builder, G_VARIANT_TYPE("a(ss)"));
    g_variant_builder_add(&hdr_builder, "(ss)", "Authorization", av.c_str());
    g_variant_builder_add(&builder, "{s@v}", "http-headers",
                          g_variant_new_variant(g_variant_builder_end(&hdr_builder)));
  }
  options = g_variant_ref_sink(g_variant_builder_end(&builder));

  if (!ostree_repo_pull_with_options(repo, remote, options, NULL, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of pulling image: " << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  OstreeDeployment *booted_deployment = Ostree::getBootedDeployment(config.sysroot);
  if (booted_deployment == NULL && !config.os.size() && !config.sysroot.size()) {
    LOGGER_LOG(LVL_error, "No booted deplyment");
    return data::InstallOutcome(data::INSTALL_FAILED, "No booted deplyment");
  }

  GKeyFile *origin = ostree_sysroot_origin_new_from_refspec(sysroot, commit.c_str());
  if (!ostree_repo_resolve_rev(repo, commit.c_str(), FALSE, &revision, &error)) {
    LOGGER_LOG(LVL_error, error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  OstreeDeployment *merge_deployment = ostree_sysroot_get_merge_deployment(sysroot, opt_osname);

  if (!ostree_sysroot_prepare_cleanup(sysroot, cancellable, &error)) {
    LOGGER_LOG(LVL_error, error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  std::ifstream args_stream("/proc/cmdline");
  std::string args_content((std::istreambuf_iterator<char>(args_stream)), std::istreambuf_iterator<char>());
  std::vector<std::string> args_vector;
  boost::split(args_vector, args_content, boost::is_any_of(" "));

  std::vector<const char *> kargs_strv_vector;
  kargs_strv_vector.reserve(args_vector.size() + 1);

  for (std::vector<std::string>::iterator it = args_vector.begin(); it != args_vector.end(); ++it) {
    kargs_strv_vector.push_back((*it).c_str());
  }
  kargs_strv_vector[args_vector.size()] = 0;
  GStrv kargs_strv = const_cast<char **>(&kargs_strv_vector[0]);

  OstreeDeployment *new_deployment = NULL;
  if (!ostree_sysroot_deploy_tree(sysroot, opt_osname, revision, origin, merge_deployment, kargs_strv, &new_deployment,
                                  cancellable, &error)) {
    LOGGER_LOG(LVL_error, "ostree_sysroot_deploy_tree: " << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  if (!ostree_sysroot_simple_write_deployment(sysroot, "", new_deployment, merge_deployment,
                                              OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN, cancellable,
                                              &error)) {
    LOGGER_LOG(LVL_error, "ostree_sysroot_simple_write_deployment:" << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }
  return data::InstallOutcome(data::OK, "Installation succesfull");
}

OstreeBranch OstreeBranch::getCurrent(const std::string &ecu_serial, const std::string &branch,
                                      const std::string &ostree_sysroot, const std::string &ostree_os) {
  OstreeDeployment *booted_deployment = Ostree::getBootedDeployment(ostree_sysroot);

  if (!booted_deployment)
    booted_deployment = ostree_sysroot_get_merge_deployment(Ostree::LoadSysroot(ostree_sysroot), ostree_os.c_str());

  GKeyFile *origin = ostree_deployment_get_origin(booted_deployment);
  const char *ref = ostree_deployment_get_csum(booted_deployment);
  char *origin_refspec = g_key_file_get_string(origin, "origin", "refspec", NULL);
  OstreePackage package(ecu_serial, (branch + "-") + ref, ref, origin_refspec, "");
  g_free(origin_refspec);
  return OstreeBranch(true, ostree_deployment_get_osname(booted_deployment), package);
}

OstreePackage OstreePackage::fromJson(const Json::Value &json) {
  return OstreePackage(json["ecu_serial"].asString(), json["ref_name"].asString(), json["commit"].asString(),
                       json["description"].asString(), json["pull_uri"].asString());
}

Json::Value OstreePackage::toEcuVersion(const Json::Value &custom) {
  Json::Value installed_image;
  installed_image["filepath"] = ref_name;
  installed_image["fileinfo"]["length"] = 0;
  installed_image["fileinfo"]["hashes"]["sha256"] = commit;

  Json::Value value;
  value["attacks_detected"] = "";
  value["installed_image"] = installed_image;
  value["ecu_serial"] = ecu_serial;
  value["previous_timeserver_time"] = "1970-01-01T00:00:00Z";
  value["timeserver_time"] = "1970-01-01T00:00:00Z";
  if (custom != Json::nullValue) {
    value["custom"] = custom;
  }
  return value;
}

OstreePackage OstreePackage::getEcu(const std::string &ecu_serial, const std::string &ostree_sysroot,
                                    const std::string &ostree_os) {
  if (boost::filesystem::exists(NEW_PACKAGE)) {
    std::ifstream path_stream(NEW_PACKAGE.c_str());
    std::string json_content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
    return OstreePackage::fromJson(json_content);
  } else {
    if (boost::filesystem::exists(BOOT_BRANCH)) {
      std::ifstream boot_branch_stream(BOOT_BRANCH.c_str());
      std::string branch_name((std::istreambuf_iterator<char>(boot_branch_stream)), std::istreambuf_iterator<char>());
      branch_name.erase(std::remove(branch_name.begin(), branch_name.end(), '\n'), branch_name.end());
      return OstreeBranch::getCurrent(ecu_serial, branch_name, ostree_sysroot, ostree_os).package;
    }
  }
  throw std::runtime_error("unknown current branch");
}
<commit_msg>Reformat with clang-format<commit_after>#include "ostree.h"
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include "logger.h"

#include <gio/gio.h>

OstreeSysroot *Ostree::LoadSysroot(const std::string &path) {
  OstreeSysroot *sysroot = NULL;

  if (path.size()) {
    sysroot = ostree_sysroot_new(g_file_new_for_path(path.c_str()));
  } else {
    sysroot = ostree_sysroot_new_default();
  }
  GCancellable *cancellable = NULL;
  GError **error = NULL;
  if (!ostree_sysroot_load(sysroot, cancellable, error)) throw std::runtime_error("could not load sysroot");
  return sysroot;
}

OstreeDeployment *Ostree::getBootedDeployment(const std::string &path) {
  OstreeSysroot *sysroot = Ostree::LoadSysroot(path);
  OstreeRepo *repo = NULL;
  OstreeDeployment *booted_deployment = NULL;

  GCancellable *cancellable = NULL;
  GError **error = NULL;

  if (!ostree_sysroot_get_repo(sysroot, &repo, cancellable, error)) throw std::runtime_error("could not get repo");

  booted_deployment = ostree_sysroot_get_booted_deployment(sysroot);
  // booted_deployment = (OstreeDeployment *)ostree_sysroot_get_deployments(sysroot)->pdata[0];
  return booted_deployment;
}

bool Ostree::addRemote(OstreeRepo *repo, const std::string &remote, const std::string &url,
                       const data::PackageManagerCredentials &cred) {
  GCancellable *cancellable = NULL;
  GError *error = NULL;
  GVariantBuilder b;
  GVariant *options;

  g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
  g_variant_builder_add(&b, "{s@v}", "gpg-verify", g_variant_new_variant(g_variant_new_boolean(FALSE)));

  if (cred.cert_file.size() && cred.pkey_file.size() && cred.ca_file.size()) {
    g_variant_builder_add(&b, "{s@v}", "tls-client-cert-path",
                          g_variant_new_variant(g_variant_new_string(cred.cert_file.c_str())));
    g_variant_builder_add(&b, "{s@v}", "tls-client-key-path",
                          g_variant_new_variant(g_variant_new_string(cred.pkey_file.c_str())));
    g_variant_builder_add(&b, "{s@v}", "tls-ca-path",
                          g_variant_new_variant(g_variant_new_string(cred.ca_file.c_str())));
  }
  options = g_variant_builder_end(&b);

  if (!ostree_repo_remote_change(repo, NULL, OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS, remote.c_str(), url.c_str(),
                                 options, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of adding remote: " << error->message);
    return false;
  }
  if (!ostree_repo_remote_change(repo, NULL, OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS, remote.c_str(), url.c_str(),
                                 options, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of adding remote: " << error->message);
    return false;
  }
  return true;
}

#include "ostree-1/ostree.h"

OstreePackage::OstreePackage(const std::string &ecu_serial_in, const std::string &ref_name_in,
                             const std::string &commit_in, const std::string &desc_in, const std::string &treehub_in)
    : ecu_serial(ecu_serial_in),
      ref_name(ref_name_in),
      commit(boost::algorithm::to_lower_copy(commit_in)),
      description(desc_in),
      pull_uri(treehub_in) {}

data::InstallOutcome OstreePackage::install(const data::PackageManagerCredentials &cred, OstreeConfig config) {
  const char remote[] = "aktualizr-remote";
  const char *const refs[] = {commit.c_str()};
  const char *opt_osname = NULL;
  OstreeRepo *repo = NULL;
  GCancellable *cancellable = NULL;
  GError *error = NULL;
  char *revision;
  GVariantBuilder builder;
  GVariant *options;

  if (config.os.size()) {
    opt_osname = config.os.c_str();
  }
  OstreeSysroot *sysroot = Ostree::LoadSysroot(config.sysroot);
  if (!ostree_sysroot_get_repo(sysroot, &repo, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "could not get repo");
    return data::InstallOutcome(data::INSTALL_FAILED, "could not get repo");
  }

  if (!Ostree::addRemote(repo, remote, pull_uri, cred)) {
    return data::InstallOutcome(data::INSTALL_FAILED, "Error of adding remote");
  }

  g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
  g_variant_builder_add(&builder, "{s@v}", "flags", g_variant_new_variant(g_variant_new_int32(0)));

  g_variant_builder_add(&builder, "{s@v}", "refs", g_variant_new_variant(g_variant_new_strv(refs, 1)));

  if (cred.access_token.size()) {
    GVariantBuilder hdr_builder;
    std::string av("Bearer ");
    av += cred.access_token;
    g_variant_builder_init(&hdr_builder, G_VARIANT_TYPE("a(ss)"));
    g_variant_builder_add(&hdr_builder, "(ss)", "Authorization", av.c_str());
    g_variant_builder_add(&builder, "{s@v}", "http-headers",
                          g_variant_new_variant(g_variant_builder_end(&hdr_builder)));
  }
  options = g_variant_ref_sink(g_variant_builder_end(&builder));

  if (!ostree_repo_pull_with_options(repo, remote, options, NULL, cancellable, &error)) {
    LOGGER_LOG(LVL_error, "Error of pulling image: " << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  OstreeDeployment *booted_deployment = Ostree::getBootedDeployment(config.sysroot);
  if (booted_deployment == NULL && !config.os.size() && !config.sysroot.size()) {
    LOGGER_LOG(LVL_error, "No booted deplyment");
    return data::InstallOutcome(data::INSTALL_FAILED, "No booted deplyment");
  }

  GKeyFile *origin = ostree_sysroot_origin_new_from_refspec(sysroot, commit.c_str());
  if (!ostree_repo_resolve_rev(repo, commit.c_str(), FALSE, &revision, &error)) {
    LOGGER_LOG(LVL_error, error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  OstreeDeployment *merge_deployment = ostree_sysroot_get_merge_deployment(sysroot, opt_osname);

  if (!ostree_sysroot_prepare_cleanup(sysroot, cancellable, &error)) {
    LOGGER_LOG(LVL_error, error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  std::ifstream args_stream("/proc/cmdline");
  std::string args_content((std::istreambuf_iterator<char>(args_stream)), std::istreambuf_iterator<char>());
  std::vector<std::string> args_vector;
  boost::split(args_vector, args_content, boost::is_any_of(" "));

  std::vector<const char *> kargs_strv_vector;
  kargs_strv_vector.reserve(args_vector.size() + 1);

  for (std::vector<std::string>::iterator it = args_vector.begin(); it != args_vector.end(); ++it) {
    kargs_strv_vector.push_back((*it).c_str());
  }
  kargs_strv_vector[args_vector.size()] = 0;
  GStrv kargs_strv = const_cast<char **>(&kargs_strv_vector[0]);

  OstreeDeployment *new_deployment = NULL;
  if (!ostree_sysroot_deploy_tree(sysroot, opt_osname, revision, origin, merge_deployment, kargs_strv, &new_deployment,
                                  cancellable, &error)) {
    LOGGER_LOG(LVL_error, "ostree_sysroot_deploy_tree: " << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }

  if (!ostree_sysroot_simple_write_deployment(sysroot, "", new_deployment, merge_deployment,
                                              OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN, cancellable,
                                              &error)) {
    LOGGER_LOG(LVL_error, "ostree_sysroot_simple_write_deployment:" << error->message);
    return data::InstallOutcome(data::INSTALL_FAILED, error->message);
  }
  return data::InstallOutcome(data::OK, "Installation succesfull");
}

OstreeBranch OstreeBranch::getCurrent(const std::string &ecu_serial, const std::string &branch,
                                      const std::string &ostree_sysroot, const std::string &ostree_os) {
  OstreeDeployment *booted_deployment = Ostree::getBootedDeployment(ostree_sysroot);

  if (!booted_deployment)
    booted_deployment = ostree_sysroot_get_merge_deployment(Ostree::LoadSysroot(ostree_sysroot), ostree_os.c_str());

  GKeyFile *origin = ostree_deployment_get_origin(booted_deployment);
  const char *ref = ostree_deployment_get_csum(booted_deployment);
  char *origin_refspec = g_key_file_get_string(origin, "origin", "refspec", NULL);
  OstreePackage package(ecu_serial, (branch + "-") + ref, ref, origin_refspec, "");
  g_free(origin_refspec);
  return OstreeBranch(true, ostree_deployment_get_osname(booted_deployment), package);
}

OstreePackage OstreePackage::fromJson(const Json::Value &json) {
  return OstreePackage(json["ecu_serial"].asString(), json["ref_name"].asString(), json["commit"].asString(),
                       json["description"].asString(), json["pull_uri"].asString());
}

Json::Value OstreePackage::toEcuVersion(const Json::Value &custom) {
  Json::Value installed_image;
  installed_image["filepath"] = ref_name;
  installed_image["fileinfo"]["length"] = 0;
  installed_image["fileinfo"]["hashes"]["sha256"] = commit;

  Json::Value value;
  value["attacks_detected"] = "";
  value["installed_image"] = installed_image;
  value["ecu_serial"] = ecu_serial;
  value["previous_timeserver_time"] = "1970-01-01T00:00:00Z";
  value["timeserver_time"] = "1970-01-01T00:00:00Z";
  if (custom != Json::nullValue) {
    value["custom"] = custom;
  }
  return value;
}

OstreePackage OstreePackage::getEcu(const std::string &ecu_serial, const std::string &ostree_sysroot,
                                    const std::string &ostree_os) {
  if (boost::filesystem::exists(NEW_PACKAGE)) {
    std::ifstream path_stream(NEW_PACKAGE.c_str());
    std::string json_content((std::istreambuf_iterator<char>(path_stream)), std::istreambuf_iterator<char>());
    return OstreePackage::fromJson(json_content);
  } else {
    if (boost::filesystem::exists(BOOT_BRANCH)) {
      std::ifstream boot_branch_stream(BOOT_BRANCH.c_str());
      std::string branch_name((std::istreambuf_iterator<char>(boot_branch_stream)), std::istreambuf_iterator<char>());
      branch_name.erase(std::remove(branch_name.begin(), branch_name.end(), '\n'), branch_name.end());
      return OstreeBranch::getCurrent(ecu_serial, branch_name, ostree_sysroot, ostree_os).package;
    }
  }
  throw std::runtime_error("unknown current branch");
}
<|endoftext|>