<commit_before>// Copyright (c) 2010 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/chromeos/frame/browser_frame_chromeos.h"

#include "chrome/browser/chromeos/frame/normal_browser_frame_view.h"
#include "chrome/browser/views/frame/browser_view.h"

// static (Factory method.)
BrowserFrame* BrowserFrame::Create(BrowserView* browser_view,
                                   Profile* profile) {
  chromeos::BrowserFrameChromeos* frame =
      new chromeos::BrowserFrameChromeos(browser_view, profile);
  frame->Init();
  return frame;
}

namespace chromeos {

BrowserFrameChromeos::BrowserFrameChromeos(
    BrowserView* browser_view, Profile* profile)
    : BrowserFrameGtk(browser_view, profile) {
}

BrowserFrameChromeos::~BrowserFrameChromeos() {
}

void BrowserFrameChromeos::Init() {
  // TODO(oshima): handle app panels. This currently uses the default
  // implementation, which opens Chrome's app panel instead of
  // ChromeOS's panel.
  if (!IsPanel()) {
    set_browser_frame_view(new NormalBrowserFrameView(this, browser_view()));
  }
  BrowserFrameGtk::Init();
}

bool BrowserFrameChromeos::IsMaximized() const {
  return !IsPanel() || WindowGtk::IsMaximized();
}

bool BrowserFrameChromeos::IsPanel() const {
  return browser_view()->IsBrowserTypePanel() ||
      browser_view()->IsBrowserTypePopup();
}

}  // namespace chromeos
<commit_msg>This fixes the crash that happens when opening dev tools/javascript console.<commit_after>// Copyright (c) 2010 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/chromeos/frame/browser_frame_chromeos.h"

#include "chrome/browser/chromeos/frame/normal_browser_frame_view.h"
#include "chrome/browser/views/frame/browser_view.h"

// static (Factory method.)
BrowserFrame* BrowserFrame::Create(BrowserView* browser_view,
                                   Profile* profile) {
  chromeos::BrowserFrameChromeos* frame =
      new chromeos::BrowserFrameChromeos(browser_view, profile);
  frame->Init();
  return frame;
}

namespace chromeos {

BrowserFrameChromeos::BrowserFrameChromeos(
    BrowserView* browser_view, Profile* profile)
    : BrowserFrameGtk(browser_view, profile) {
}

BrowserFrameChromeos::~BrowserFrameChromeos() {
}

void BrowserFrameChromeos::Init() {
  // Excludes a browser intance that requires icon/title. This is typically true
  // for dev tools and javascript console.
  // TODO(oshima): handle app panels. This currently uses the default
  // implementation, which opens Chrome's app panel instead of
  // ChromeOS's panel.
  if (!IsPanel() &&
      !browser_view()->ShouldShowWindowIcon() &&
      !browser_view()->ShouldShowWindowTitle()) {
    set_browser_frame_view(new NormalBrowserFrameView(this, browser_view()));
  }
  BrowserFrameGtk::Init();
}

bool BrowserFrameChromeos::IsMaximized() const {
  return !IsPanel() || WindowGtk::IsMaximized();
}

bool BrowserFrameChromeos::IsPanel() const {
  return browser_view()->IsBrowserTypePanel() ||
      browser_view()->IsBrowserTypePopup();
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2009 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 "base/ref_counted.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/extensions/autoupdate_interceptor.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"

class ExtensionManagementTest : public ExtensionBrowserTest {
 protected:
  // Helper method that returns whether the extension is at the given version.
  // This calls version(), which must be defined in the extension's bg page,
  // as well as asking the extension itself.
  bool IsExtensionAtVersion(Extension* extension,
                            const std::string& expected_version) {
    // Test that the extension's version from the manifest and reported by the
    // background page is correct.  This is to ensure that the processes are in
    // sync with the Extension.
    ExtensionProcessManager* manager = browser()->profile()->
        GetExtensionProcessManager();
    ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension);
    EXPECT_TRUE(ext_host);
    if (!ext_host)
      return false;

    std::string version_from_bg;
    bool exec = ui_test_utils::ExecuteJavaScriptAndExtractString(
        ext_host->render_view_host(), L"", L"version()", &version_from_bg);
    EXPECT_TRUE(exec);
    if (!exec)
      return false;

    if (version_from_bg != expected_version ||
        extension->VersionString() != expected_version)
      return false;
    return true;
  }

  // Helper method that installs a low permission extension then updates
  // to the second version requiring increased permissions. Returns whether
  // the operation was completed successfully.
  bool InstallAndUpdateIncreasingPermissionsExtension() {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    TabContents* contents = browser()->GetSelectedTabContents();
    if (service->HasInstalledExtensions() || !contents)
      return false;

    // Install the initial version, which should happen just fine.
    if (!InstallExtension(
        test_data_dir_.AppendASCII("permissions-low-v1.crx"), 1))
      return false;
    EXPECT_EQ(0, contents->infobar_delegate_count());

    // Upgrade to a version that wants more permissions. We should disable the
    // extension and prompt the user to reenable.
    if (service->extensions()->size() != 1u)
      return false;
    if (!UpdateExtension(
        service->extensions()->at(0)->id(),
        test_data_dir_.AppendASCII("permissions-high-v2.crx"), -1))
      return false;
    EXPECT_EQ(1, contents->infobar_delegate_count());
    EXPECT_EQ(0u, service->extensions()->size());
    if (service->disabled_extensions()->size() != 1u)
      return false;
    return true;
  }
};

// Tests that installing the same version does not overwrite.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));

  // Install an extension with the same version. The previous install should
  // be kept.
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install_same_version.crx"), 0));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install_older_version.crx"), 0));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));

  // Cancel this install.
  StartInstallButCancel(test_data_dir_.AppendASCII("install/install_v2.crx"));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

// Tests that installing and uninstalling extensions don't crash with an
// incognito window open.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
  // Open an incognito window to the extensions management page.  We just
  // want to make sure that we don't crash while playing with extensions when
  // this guy is around.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
                                     GURL(chrome::kChromeUIExtensionsURL));

  ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1));
  UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
}

// Tests the process of updating an extension to one that requires higher
// permissions.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UpdatePermissions) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());

  // Now try reenabling it, which should also dismiss the infobar.
  service->EnableExtension(service->disabled_extensions()->at(0)->id());
  TabContents* contents = browser()->GetSelectedTabContents();
  ASSERT_TRUE(contents);
  EXPECT_EQ(0, contents->infobar_delegate_count());
  EXPECT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
}

// Tests that we can uninstall a disabled extension.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, UninstallDisabled) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());

  // Now try uninstalling it.
  UninstallExtension(service->disabled_extensions()->at(0)->id());
  EXPECT_EQ(0u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  ASSERT_FALSE(service->HasInstalledExtensions());
}

// Tests that disabling and re-enabling an extension works.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
  ExtensionProcessManager* manager = browser()->profile()->
      GetExtensionProcessManager();
  ExtensionsService* service = browser()->profile()->GetExtensionsService();

  // Load an extension, expect the background page to be available.
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
                    .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
                    .AppendASCII("1.0")));
  ASSERT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  Extension* extension = service->extensions()->at(0);
  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());

  // After disabling, the background page should go away.
  service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
  EXPECT_EQ(0u, service->extensions()->size());
  EXPECT_EQ(1u, service->disabled_extensions()->size());
  EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());

  // And bring it back.
  service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
  EXPECT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());
}

// TODO(asargent): This test seems to crash on linux buildbots.
// (http://crbug.com/31737)
#if !defined(OS_LINUX)
// Tests extension autoupdate.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
  FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
  // Note: This interceptor gets requests on the IO thread.
  scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
  URLFetcher::enable_interception_for_tests(true);

  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
                                     basedir.AppendASCII("manifest_v2.xml"));
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
                                     basedir.AppendASCII("v2.crx"));

  // Install version 1 of the extension.
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
  const ExtensionList* extensions = service->extensions();
  ASSERT_TRUE(service->HasInstalledExtensions());
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("1.0", extensions->at(0)->VersionString());

  // We don't want autoupdate blacklist checks.
  service->updater()->set_blacklist_checks_enabled(false);

  // Run autoupdate and make sure version 2 of the extension was installed.
  service->updater()->CheckNow();
  ASSERT_TRUE(WaitForExtensionInstall());
  extensions = service->extensions();
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("2.0", extensions->at(0)->VersionString());

  // Now try doing an update to version 3, which has been incorrectly
  // signed. This should fail.
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
                                     basedir.AppendASCII("manifest_v3.xml"));
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v3.crx",
                                     basedir.AppendASCII("v3.crx"));

  service->updater()->CheckNow();
  ASSERT_TRUE(WaitForExtensionInstallError());

  // Make sure the extension state is the same as before.
  extensions = service->extensions();
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("2.0", extensions->at(0)->VersionString());
}
#endif  // !defined(OS_LINUX)
<commit_msg>Disable UninstallDisabled and UpdatePermissions temporarily. BUG=none TEST=none TBR=asargent Review URL: http://codereview.chromium.org/552077<commit_after>// Copyright (c) 2009 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 "base/ref_counted.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/extensions/autoupdate_interceptor.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"

class ExtensionManagementTest : public ExtensionBrowserTest {
 protected:
  // Helper method that returns whether the extension is at the given version.
  // This calls version(), which must be defined in the extension's bg page,
  // as well as asking the extension itself.
  bool IsExtensionAtVersion(Extension* extension,
                            const std::string& expected_version) {
    // Test that the extension's version from the manifest and reported by the
    // background page is correct.  This is to ensure that the processes are in
    // sync with the Extension.
    ExtensionProcessManager* manager = browser()->profile()->
        GetExtensionProcessManager();
    ExtensionHost* ext_host = manager->GetBackgroundHostForExtension(extension);
    EXPECT_TRUE(ext_host);
    if (!ext_host)
      return false;

    std::string version_from_bg;
    bool exec = ui_test_utils::ExecuteJavaScriptAndExtractString(
        ext_host->render_view_host(), L"", L"version()", &version_from_bg);
    EXPECT_TRUE(exec);
    if (!exec)
      return false;

    if (version_from_bg != expected_version ||
        extension->VersionString() != expected_version)
      return false;
    return true;
  }

  // Helper method that installs a low permission extension then updates
  // to the second version requiring increased permissions. Returns whether
  // the operation was completed successfully.
  bool InstallAndUpdateIncreasingPermissionsExtension() {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    TabContents* contents = browser()->GetSelectedTabContents();
    if (service->HasInstalledExtensions() || !contents)
      return false;

    // Install the initial version, which should happen just fine.
    if (!InstallExtension(
        test_data_dir_.AppendASCII("permissions-low-v1.crx"), 1))
      return false;
    EXPECT_EQ(0, contents->infobar_delegate_count());

    // Upgrade to a version that wants more permissions. We should disable the
    // extension and prompt the user to reenable.
    if (service->extensions()->size() != 1u)
      return false;
    if (!UpdateExtension(
        service->extensions()->at(0)->id(),
        test_data_dir_.AppendASCII("permissions-high-v2.crx"), -1))
      return false;
    EXPECT_EQ(1, contents->infobar_delegate_count());
    EXPECT_EQ(0u, service->extensions()->size());
    if (service->disabled_extensions()->size() != 1u)
      return false;
    return true;
  }
};

// Tests that installing the same version does not overwrite.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallSameVersion) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));

  // Install an extension with the same version. The previous install should
  // be kept.
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install_same_version.crx"), 0));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallOlderVersion) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install_older_version.crx"), 0));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(
      test_data_dir_.AppendASCII("install/install.crx"), 1));

  // Cancel this install.
  StartInstallButCancel(test_data_dir_.AppendASCII("install/install_v2.crx"));
  EXPECT_TRUE(IsExtensionAtVersion(service->extensions()->at(0), "1.0"));
}

// Tests that installing and uninstalling extensions don't crash with an
// incognito window open.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
  // Open an incognito window to the extensions management page.  We just
  // want to make sure that we don't crash while playing with extensions when
  // this guy is around.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
                                     GURL(chrome::kChromeUIExtensionsURL));

  ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1));
  UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
}

// Tests the process of updating an extension to one that requires higher
// permissions.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DISABLED_UpdatePermissions) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());

  // Now try reenabling it, which should also dismiss the infobar.
  service->EnableExtension(service->disabled_extensions()->at(0)->id());
  TabContents* contents = browser()->GetSelectedTabContents();
  ASSERT_TRUE(contents);
  EXPECT_EQ(0, contents->infobar_delegate_count());
  EXPECT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
}

// Tests that we can uninstall a disabled extension.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DISABLED_UninstallDisabled) {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_TRUE(InstallAndUpdateIncreasingPermissionsExtension());

  // Now try uninstalling it.
  UninstallExtension(service->disabled_extensions()->at(0)->id());
  EXPECT_EQ(0u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  ASSERT_FALSE(service->HasInstalledExtensions());
}

// Tests that disabling and re-enabling an extension works.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, DisableEnable) {
  ExtensionProcessManager* manager = browser()->profile()->
      GetExtensionProcessManager();
  ExtensionsService* service = browser()->profile()->GetExtensionsService();

  // Load an extension, expect the background page to be available.
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("good").AppendASCII("Extensions")
                    .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
                    .AppendASCII("1.0")));
  ASSERT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  Extension* extension = service->extensions()->at(0);
  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());

  // After disabling, the background page should go away.
  service->DisableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
  EXPECT_EQ(0u, service->extensions()->size());
  EXPECT_EQ(1u, service->disabled_extensions()->size());
  EXPECT_FALSE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());

  // And bring it back.
  service->EnableExtension("bjafgdebaacbbbecmhlhpofkepfkgcpa");
  EXPECT_EQ(1u, service->extensions()->size());
  EXPECT_EQ(0u, service->disabled_extensions()->size());
  EXPECT_TRUE(manager->GetBackgroundHostForExtension(extension));
  ASSERT_TRUE(service->HasInstalledExtensions());
}

// TODO(asargent): This test seems to crash on linux buildbots.
// (http://crbug.com/31737)
#if !defined(OS_LINUX)
// Tests extension autoupdate.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, AutoUpdate) {
  FilePath basedir = test_data_dir_.AppendASCII("autoupdate");
  // Note: This interceptor gets requests on the IO thread.
  scoped_refptr<AutoUpdateInterceptor> interceptor(new AutoUpdateInterceptor());
  URLFetcher::enable_interception_for_tests(true);

  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
                                     basedir.AppendASCII("manifest_v2.xml"));
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v2.crx",
                                     basedir.AppendASCII("v2.crx"));

  // Install version 1 of the extension.
  ExtensionsService* service = browser()->profile()->GetExtensionsService();
  ASSERT_FALSE(service->HasInstalledExtensions());
  ASSERT_TRUE(InstallExtension(basedir.AppendASCII("v1.crx"), 1));
  const ExtensionList* extensions = service->extensions();
  ASSERT_TRUE(service->HasInstalledExtensions());
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("1.0", extensions->at(0)->VersionString());

  // We don't want autoupdate blacklist checks.
  service->updater()->set_blacklist_checks_enabled(false);

  // Run autoupdate and make sure version 2 of the extension was installed.
  service->updater()->CheckNow();
  ASSERT_TRUE(WaitForExtensionInstall());
  extensions = service->extensions();
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("2.0", extensions->at(0)->VersionString());

  // Now try doing an update to version 3, which has been incorrectly
  // signed. This should fail.
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/manifest",
                                     basedir.AppendASCII("manifest_v3.xml"));
  interceptor->SetResponseOnIOThread("http://localhost/autoupdate/v3.crx",
                                     basedir.AppendASCII("v3.crx"));

  service->updater()->CheckNow();
  ASSERT_TRUE(WaitForExtensionInstallError());

  // Make sure the extension state is the same as before.
  extensions = service->extensions();
  ASSERT_EQ(1u, extensions->size());
  ASSERT_EQ("ogjcoiohnmldgjemafoockdghcjciccf", extensions->at(0)->id());
  ASSERT_EQ("2.0", extensions->at(0)->VersionString());
}
#endif  // !defined(OS_LINUX)
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/net/resolve_proxy_msg_helper.h"

#include "base/waitable_event.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"

// This ProxyConfigService always returns "http://pac" as the PAC url to use.
class MockProxyConfigService: public net::ProxyConfigService {
 public:
  virtual int GetProxyConfig(net::ProxyConfig* results) {
    results->pac_url = GURL("http://pac");
    return net::OK;
  }
};

// This PAC resolver always returns the hostname of the query URL as the
// proxy to use. The Block() method will make GetProxyForURL() hang until
// Unblock() is called.
class MockProxyResolver : public net::ProxyResolver {
 public:
  explicit MockProxyResolver() : event_(false, false), is_blocked_(false) {
  }

  virtual int GetProxyForURL(const GURL& query_url,
                             const GURL& /*pac_url*/,
                             net::ProxyInfo* results) {
    if (is_blocked_)
      event_.Wait();
    results->UseNamedProxy(query_url.host());
    return net::OK;
  }

  void Block() {
    is_blocked_ = true;
    event_.Reset();
  }

  void Unblock() {
    is_blocked_ = false;
    event_.Signal();
  }

 private:
  base::WaitableEvent event_;
  bool is_blocked_;
};

// This struct holds the values that were passed to
// Delegate::OnResolveProxyCompleted(). The caller should use WaitUntilDone()
// to block until the result has been populated.
struct ResultFuture {
 public:
  ResultFuture()
      : reply_msg(NULL),
        error_code(0),
        started_(false, false),
        completed_(false, false) {
  }

  // Wait until the request has completed. In other words we have invoked:
  // ResolveProxyMsgHelper::Delegate::OnResolveProxyCompleted.
  void WaitUntilDone() {
    completed_.Wait();
  }

  // Wait until the request has been sent to ResolveProxyMsgHelper.
  void WaitUntilStarted() {
    started_.Wait();
  }

  bool TimedWaitUntilDone(const base::TimeDelta& max_time) {
    return completed_.TimedWait(max_time);
  }

  // These fields are only valid after returning from WaitUntilDone().
  IPC::Message* reply_msg;
  int error_code;
  std::string proxy_list;

 private:
  friend class AsyncRequestRunner;
  base::WaitableEvent started_;
  base::WaitableEvent completed_;
};

// This class lives on the io thread. It starts async requests using the
// class under test (ResolveProxyMsgHelper), and signals the result future on
// completion.
class AsyncRequestRunner : public ResolveProxyMsgHelper::Delegate {
 public:
  AsyncRequestRunner(net::ProxyService* proxy_service) {
    resolve_proxy_msg_helper_.reset(
        new ResolveProxyMsgHelper(this, proxy_service));
  }

  void Start(ResultFuture* future, const GURL& url, IPC::Message* reply_msg) {
    futures_.push_back(future);
    resolve_proxy_msg_helper_->Start(url, reply_msg);

    // Notify of request start.
    future->started_.Signal();
  }

  virtual void OnResolveProxyCompleted(IPC::Message* reply_msg,
                                       int error_code,
                                       const std::string& proxy_list) {
    // Update the result future for this request (top of queue), and signal it.
    ResultFuture* future = futures_.front();
    futures_.pop_front();

    future->reply_msg = reply_msg;
    future->error_code = error_code;
    future->proxy_list = proxy_list;

    // Notify of request completion.
    future->completed_.Signal();
  }

 private:
  std::deque<ResultFuture*> futures_;
  scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_;
};

// Helper class to start async requests on an io thread, and return a
// result future. The caller then uses ResultFuture::WaitUntilDone() to
// get at the results. It "bridges" the originating thread with the helper
// io thread.
class RunnerBridge {
 public:
  RunnerBridge() : io_thread_("io_thread"), done_(true, false) {
    // Start an io thread where we will run the async requests.
    base::Thread::Options options;
    options.message_loop_type = MessageLoop::TYPE_IO;
    io_thread_.StartWithOptions(options);

    // Construct the state that lives on io thread.
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoConstruct));
    done_.Wait();
  }

  // Start an async request on the io thread.
  ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) {
    ResultFuture* future = new ResultFuture();

    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        async_runner_, &AsyncRequestRunner::Start, future, url, reply_msg));

    return future;
  }

  void DestroyAsyncRunner() {
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoDestroyAsyncRunner));
    done_.Wait();
  }

  ~RunnerBridge() {
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoDestroy));
    done_.Wait();
  }

  MockProxyResolver* proxy_resolver() {
    return proxy_resolver_;
  }

  // Called from io thread.
  void DoConstruct() {
    proxy_resolver_ = new MockProxyResolver();
    proxy_service_ = new net::ProxyService(new MockProxyConfigService(),
                                           proxy_resolver_);
    async_runner_ = new AsyncRequestRunner(proxy_service_);
    done_.Signal();
  }

  // Called from io thread.
  void DoDestroy() {
    delete async_runner_;
    delete proxy_service_;
    done_.Signal();
  }

  // Called from io thread.
  void DoDestroyAsyncRunner() {
    delete async_runner_;
    async_runner_ = NULL;
    done_.Signal();
  }

 private:
  base::Thread io_thread_;
  base::WaitableEvent done_;

  net::ProxyService* proxy_service_;
  MockProxyResolver* proxy_resolver_;  // Owned by proxy_service_.

  AsyncRequestRunner* async_runner_;
};

// Avoid the need to have an AddRef / Release
template<>
void RunnableMethodTraits<RunnerBridge>::RetainCallee(RunnerBridge*) {}
template<>
void RunnableMethodTraits<RunnerBridge>::ReleaseCallee(RunnerBridge*) {}

template<>
void RunnableMethodTraits<AsyncRequestRunner>::RetainCallee(AsyncRequestRunner*) {}
template<>
void RunnableMethodTraits<AsyncRequestRunner>::ReleaseCallee(AsyncRequestRunner*) {}

// Issue three sequential requests -- each should succeed.
TEST(ResolveProxyMsgHelperTest, Sequential) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  scoped_ptr<IPC::Message> msg1(new IPC::Message());
  scoped_ptr<IPC::Message> msg2(new IPC::Message());
  scoped_ptr<IPC::Message> msg3(new IPC::Message());

  // Execute each request sequentially (so there are never 2 requests
  // outstanding at the same time).

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get()));
  result1->WaitUntilDone();

  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get()));
  result2->WaitUntilDone();

  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get()));
  result3->WaitUntilDone();

  // Check that each request gave the expected result.

  EXPECT_EQ(msg1.get(), result1->reply_msg);
  EXPECT_EQ(net::OK, result1->error_code);
  EXPECT_EQ("PROXY www.google1.com", result1->proxy_list);

  EXPECT_EQ(msg2.get(), result2->reply_msg);
  EXPECT_EQ(net::OK, result2->error_code);
  EXPECT_EQ("PROXY www.google2.com", result2->proxy_list);

  EXPECT_EQ(msg3.get(), result3->reply_msg);
  EXPECT_EQ(net::OK, result3->error_code);
  EXPECT_EQ("PROXY www.google3.com", result3->proxy_list);
}

// Issue a request while one is already in progress -- should be queued.
TEST(ResolveProxyMsgHelperTest, QueueRequests) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  scoped_ptr<IPC::Message> msg1(new IPC::Message());
  scoped_ptr<IPC::Message> msg2(new IPC::Message());
  scoped_ptr<IPC::Message> msg3(new IPC::Message());

  // Make the proxy resolver hang on the next request.
  runner.proxy_resolver()->Block();

  // Start three requests. Since the proxy resolver is hung, the second two
  // will be pending.

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get()));
  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get()));
  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get()));

  // Wait for the final request to have been scheduled. Otherwise we may rush
  // to calling Unblock() without actually having blocked anything.
  result3->WaitUntilStarted();

  // Unblock the proxy service so requests 1-3 can complete.
  runner.proxy_resolver()->Unblock();

  // Wait for all the requests to finish (they run in FIFO order).
  result3->WaitUntilDone();

  // Check that each call invoked the callback with the right parameters.

  EXPECT_EQ(msg1.get(), result1->reply_msg);
  EXPECT_EQ(net::OK, result1->error_code);
  EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list);

  EXPECT_EQ(msg2.get(), result2->reply_msg);
  EXPECT_EQ(net::OK, result2->error_code);
  EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list);

  EXPECT_EQ(msg3.get(), result3->reply_msg);
  EXPECT_EQ(net::OK, result3->error_code);
  EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list);
}

// Delete the helper while a request is in progress, and others are pending.
TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  // NOTE: these are not scoped ptr, since they will be deleted by the
  // request's cancellation.
  IPC::Message* msg1 = new IPC::Message();
  IPC::Message* msg2 = new IPC::Message();
  IPC::Message* msg3 = new IPC::Message();

  // Make the next request block.
  runner.proxy_resolver()->Block();

  // Start three requests; since the first one blocked, the other two should
  // be pending.

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1));
  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2));
  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3));

  result3->WaitUntilStarted();

  // Delete the underlying ResolveProxyMsgHelper -- this should cancel all
  // the requests which are outstanding.
  runner.DestroyAsyncRunner();

  // Unblocking the proxy resolver means the three requests can complete --
  // however they should not try to notify the delegate since we have already
  // deleted the helper.
  runner.proxy_resolver()->Unblock();

  // Check that none of the requests were sent to the delegate.
  EXPECT_FALSE(
      result1->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));
  EXPECT_FALSE(
      result2->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));
  EXPECT_FALSE(
      result3->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));

  // It should also be the case that msg1, msg2, msg3 were deleted by the
  // cancellation. (Else will show up as a leak in Purify).
}

<commit_msg>Update test expectation. This needs the port numbers, since they now get properly inferred.<commit_after>// Copyright (c) 2009 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/net/resolve_proxy_msg_helper.h"

#include "base/waitable_event.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"

// This ProxyConfigService always returns "http://pac" as the PAC url to use.
class MockProxyConfigService: public net::ProxyConfigService {
 public:
  virtual int GetProxyConfig(net::ProxyConfig* results) {
    results->pac_url = GURL("http://pac");
    return net::OK;
  }
};

// This PAC resolver always returns the hostname of the query URL as the
// proxy to use. The Block() method will make GetProxyForURL() hang until
// Unblock() is called.
class MockProxyResolver : public net::ProxyResolver {
 public:
  explicit MockProxyResolver() : event_(false, false), is_blocked_(false) {
  }

  virtual int GetProxyForURL(const GURL& query_url,
                             const GURL& /*pac_url*/,
                             net::ProxyInfo* results) {
    if (is_blocked_)
      event_.Wait();
    results->UseNamedProxy(query_url.host());
    return net::OK;
  }

  void Block() {
    is_blocked_ = true;
    event_.Reset();
  }

  void Unblock() {
    is_blocked_ = false;
    event_.Signal();
  }

 private:
  base::WaitableEvent event_;
  bool is_blocked_;
};

// This struct holds the values that were passed to
// Delegate::OnResolveProxyCompleted(). The caller should use WaitUntilDone()
// to block until the result has been populated.
struct ResultFuture {
 public:
  ResultFuture()
      : reply_msg(NULL),
        error_code(0),
        started_(false, false),
        completed_(false, false) {
  }

  // Wait until the request has completed. In other words we have invoked:
  // ResolveProxyMsgHelper::Delegate::OnResolveProxyCompleted.
  void WaitUntilDone() {
    completed_.Wait();
  }

  // Wait until the request has been sent to ResolveProxyMsgHelper.
  void WaitUntilStarted() {
    started_.Wait();
  }

  bool TimedWaitUntilDone(const base::TimeDelta& max_time) {
    return completed_.TimedWait(max_time);
  }

  // These fields are only valid after returning from WaitUntilDone().
  IPC::Message* reply_msg;
  int error_code;
  std::string proxy_list;

 private:
  friend class AsyncRequestRunner;
  base::WaitableEvent started_;
  base::WaitableEvent completed_;
};

// This class lives on the io thread. It starts async requests using the
// class under test (ResolveProxyMsgHelper), and signals the result future on
// completion.
class AsyncRequestRunner : public ResolveProxyMsgHelper::Delegate {
 public:
  AsyncRequestRunner(net::ProxyService* proxy_service) {
    resolve_proxy_msg_helper_.reset(
        new ResolveProxyMsgHelper(this, proxy_service));
  }

  void Start(ResultFuture* future, const GURL& url, IPC::Message* reply_msg) {
    futures_.push_back(future);
    resolve_proxy_msg_helper_->Start(url, reply_msg);

    // Notify of request start.
    future->started_.Signal();
  }

  virtual void OnResolveProxyCompleted(IPC::Message* reply_msg,
                                       int error_code,
                                       const std::string& proxy_list) {
    // Update the result future for this request (top of queue), and signal it.
    ResultFuture* future = futures_.front();
    futures_.pop_front();

    future->reply_msg = reply_msg;
    future->error_code = error_code;
    future->proxy_list = proxy_list;

    // Notify of request completion.
    future->completed_.Signal();
  }

 private:
  std::deque<ResultFuture*> futures_;
  scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_;
};

// Helper class to start async requests on an io thread, and return a
// result future. The caller then uses ResultFuture::WaitUntilDone() to
// get at the results. It "bridges" the originating thread with the helper
// io thread.
class RunnerBridge {
 public:
  RunnerBridge() : io_thread_("io_thread"), done_(true, false) {
    // Start an io thread where we will run the async requests.
    base::Thread::Options options;
    options.message_loop_type = MessageLoop::TYPE_IO;
    io_thread_.StartWithOptions(options);

    // Construct the state that lives on io thread.
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoConstruct));
    done_.Wait();
  }

  // Start an async request on the io thread.
  ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) {
    ResultFuture* future = new ResultFuture();

    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        async_runner_, &AsyncRequestRunner::Start, future, url, reply_msg));

    return future;
  }

  void DestroyAsyncRunner() {
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoDestroyAsyncRunner));
    done_.Wait();
  }

  ~RunnerBridge() {
    io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &RunnerBridge::DoDestroy));
    done_.Wait();
  }

  MockProxyResolver* proxy_resolver() {
    return proxy_resolver_;
  }

  // Called from io thread.
  void DoConstruct() {
    proxy_resolver_ = new MockProxyResolver();
    proxy_service_ = new net::ProxyService(new MockProxyConfigService(),
                                           proxy_resolver_);
    async_runner_ = new AsyncRequestRunner(proxy_service_);
    done_.Signal();
  }

  // Called from io thread.
  void DoDestroy() {
    delete async_runner_;
    delete proxy_service_;
    done_.Signal();
  }

  // Called from io thread.
  void DoDestroyAsyncRunner() {
    delete async_runner_;
    async_runner_ = NULL;
    done_.Signal();
  }

 private:
  base::Thread io_thread_;
  base::WaitableEvent done_;

  net::ProxyService* proxy_service_;
  MockProxyResolver* proxy_resolver_;  // Owned by proxy_service_.

  AsyncRequestRunner* async_runner_;
};

// Avoid the need to have an AddRef / Release
template<>
void RunnableMethodTraits<RunnerBridge>::RetainCallee(RunnerBridge*) {}
template<>
void RunnableMethodTraits<RunnerBridge>::ReleaseCallee(RunnerBridge*) {}

template<>
void RunnableMethodTraits<AsyncRequestRunner>::RetainCallee(AsyncRequestRunner*) {}
template<>
void RunnableMethodTraits<AsyncRequestRunner>::ReleaseCallee(AsyncRequestRunner*) {}

// Issue three sequential requests -- each should succeed.
TEST(ResolveProxyMsgHelperTest, Sequential) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  scoped_ptr<IPC::Message> msg1(new IPC::Message());
  scoped_ptr<IPC::Message> msg2(new IPC::Message());
  scoped_ptr<IPC::Message> msg3(new IPC::Message());

  // Execute each request sequentially (so there are never 2 requests
  // outstanding at the same time).

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get()));
  result1->WaitUntilDone();

  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get()));
  result2->WaitUntilDone();

  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get()));
  result3->WaitUntilDone();

  // Check that each request gave the expected result.

  EXPECT_EQ(msg1.get(), result1->reply_msg);
  EXPECT_EQ(net::OK, result1->error_code);
  EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list);

  EXPECT_EQ(msg2.get(), result2->reply_msg);
  EXPECT_EQ(net::OK, result2->error_code);
  EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list);

  EXPECT_EQ(msg3.get(), result3->reply_msg);
  EXPECT_EQ(net::OK, result3->error_code);
  EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list);
}

// Issue a request while one is already in progress -- should be queued.
TEST(ResolveProxyMsgHelperTest, QueueRequests) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  scoped_ptr<IPC::Message> msg1(new IPC::Message());
  scoped_ptr<IPC::Message> msg2(new IPC::Message());
  scoped_ptr<IPC::Message> msg3(new IPC::Message());

  // Make the proxy resolver hang on the next request.
  runner.proxy_resolver()->Block();

  // Start three requests. Since the proxy resolver is hung, the second two
  // will be pending.

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get()));
  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get()));
  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get()));

  // Wait for the final request to have been scheduled. Otherwise we may rush
  // to calling Unblock() without actually having blocked anything.
  result3->WaitUntilStarted();

  // Unblock the proxy service so requests 1-3 can complete.
  runner.proxy_resolver()->Unblock();

  // Wait for all the requests to finish (they run in FIFO order).
  result3->WaitUntilDone();

  // Check that each call invoked the callback with the right parameters.

  EXPECT_EQ(msg1.get(), result1->reply_msg);
  EXPECT_EQ(net::OK, result1->error_code);
  EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list);

  EXPECT_EQ(msg2.get(), result2->reply_msg);
  EXPECT_EQ(net::OK, result2->error_code);
  EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list);

  EXPECT_EQ(msg3.get(), result3->reply_msg);
  EXPECT_EQ(net::OK, result3->error_code);
  EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list);
}

// Delete the helper while a request is in progress, and others are pending.
TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) {
  RunnerBridge runner;

  GURL url1("http://www.google1.com/");
  GURL url2("http://www.google2.com/");
  GURL url3("http://www.google3.com/");

  // NOTE: these are not scoped ptr, since they will be deleted by the
  // request's cancellation.
  IPC::Message* msg1 = new IPC::Message();
  IPC::Message* msg2 = new IPC::Message();
  IPC::Message* msg3 = new IPC::Message();

  // Make the next request block.
  runner.proxy_resolver()->Block();

  // Start three requests; since the first one blocked, the other two should
  // be pending.

  scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1));
  scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2));
  scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3));

  result3->WaitUntilStarted();

  // Delete the underlying ResolveProxyMsgHelper -- this should cancel all
  // the requests which are outstanding.
  runner.DestroyAsyncRunner();

  // Unblocking the proxy resolver means the three requests can complete --
  // however they should not try to notify the delegate since we have already
  // deleted the helper.
  runner.proxy_resolver()->Unblock();

  // Check that none of the requests were sent to the delegate.
  EXPECT_FALSE(
      result1->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));
  EXPECT_FALSE(
      result2->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));
  EXPECT_FALSE(
      result3->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2)));

  // It should also be the case that msg1, msg2, msg3 were deleted by the
  // cancellation. (Else will show up as a leak in Purify).
}

<|endoftext|>


<commit_before>/*  Sirikata
 *  SingleMaterialGeometryFilter.cpp
 *
 *  Copyright (c) 2010, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "SingleMaterialGeometryFilter.hpp"
#include <sirikata/mesh/Meshdata.hpp>

namespace Sirikata {
namespace Mesh {

SingleMaterialGeometryFilter::SingleMaterialGeometryFilter(const String& args) {
}

FilterDataPtr SingleMaterialGeometryFilter::apply(FilterDataPtr input) {
    for(FilterData::const_iterator md_it = input->begin(); md_it != input->end(); md_it++) {
        VisualPtr vis = *md_it;
        // Meshdata only currently
        MeshdataPtr md( std::tr1::dynamic_pointer_cast<Meshdata>(vis) );
        if (!md) continue;

        // Our approach is to run through all SubMeshGeometries generating
        // versions that are split. By maintaining a map from old indices to a
        // list of new indices, we can then run through all GeometryInstances,
        // duplicating them for each part of the original instance.

        // This map stores geometryIndex -> list of new geometry indices,
        // allowing the old instances to be split into a set of new instances
        typedef std::map<uint32, std::vector<uint32> > OldToNewIndexMap;
        OldToNewIndexMap new_geo_indices;

        // Our output should be a new set of SubMeshGeometries and a new set of
        // GeometryInstances referring to them.
        SubMeshGeometryList new_geometry;
        GeometryInstanceList new_instances;

        for(uint32 geo_idx = 0; geo_idx < md->geometry.size(); geo_idx++) {
            SubMeshGeometry& geo = md->geometry[geo_idx];

            // This mesh needs to be split into several new meshes, by material.
            typedef std::map<SubMeshGeometry::Primitive::MaterialId, SubMeshGeometry> SingleMatMeshMap;
            SingleMatMeshMap new_meshes;
            for(uint32 pi = 0; pi < geo.primitives.size(); pi++) {
                SubMeshGeometry::Primitive& prim = geo.primitives[pi];
                // Create new submesh if there isn't one for this material id yet
                if (new_meshes.find(prim.materialId) == new_meshes.end()) {
                    // Copy all data
                    new_meshes[prim.materialId] = geo;
                    // And clear the prim list
                    new_meshes[prim.materialId].primitives.clear();
                }
                // Add this primitive
                new_meshes[prim.materialId].primitives.push_back(prim);
                // Reset material id -- all should be 0 since all will only have
                // 1 material id
                new_meshes[prim.materialId].primitives.back().materialId = 0;
            }
            // Recompute summary info for these new submeshes, add them to the
            // new set, and store their indices for use by the instance
            // geometries
            typedef std::map<SubMeshGeometry::Primitive::MaterialId, uint32> NewSubMeshIndexMap;
            NewSubMeshIndexMap new_indices_by_material;
            for(SingleMatMeshMap::iterator nm_it = new_meshes.begin(); nm_it != new_meshes.end(); nm_it++) {
                nm_it->second.recomputeBounds();
                uint32 new_index = new_geometry.size();
                new_geometry.push_back(nm_it->second);
                new_indices_by_material[nm_it->first] = new_index;
            }

            // Now, run through and find GeometryInstances which are using the
            // original mesh and make new ones using all the split ones
            for(uint32 ii = 0; ii < md->instances.size(); ii++) {
                GeometryInstance& geo_inst = md->instances[ii];
                if (geo_inst.geometryIndex != geo_idx) continue;

                for(NewSubMeshIndexMap::iterator sm_it = new_indices_by_material.begin(); sm_it != new_indices_by_material.end(); sm_it++) {
                    new_instances.push_back(geo_inst);
                    // Point to new index
                    new_instances.back().geometryIndex = sm_it->second;
                    // Reset material binding map, using only the material bound
                    // for this material from the earlier version.
                    new_instances.back().materialBindingMap.clear();
                    new_instances.back().materialBindingMap[0] = geo_inst.materialBindingMap[sm_it->first];
                }
            }
        }

        // After all the translation, just swapping out the list of
        // SubMeshGeometries and GeometryInstances should be safe
        md->geometry = new_geometry;
        md->instances = new_instances;
    }

    return input;
}

} // namespace Mesh
} // namespace Sirikata
<commit_msg>Make SingleMaterialGeometryFilter use much less memory.<commit_after>/*  Sirikata
 *  SingleMaterialGeometryFilter.cpp
 *
 *  Copyright (c) 2010, Ewen Cheslack-Postava
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "SingleMaterialGeometryFilter.hpp"
#include <sirikata/mesh/Meshdata.hpp>

namespace Sirikata {
namespace Mesh {

SingleMaterialGeometryFilter::SingleMaterialGeometryFilter(const String& args) {
}

namespace {

/** Clone this SubMeshGeometry, taking only a subset of its elements. Because
 *  copying requires duplicating the underlying data, this also removes
 *  now-unused data from the underlying vertex data in the copy. NOTE: Currently
 *  only supports a single material, i.e. all copied primitives should use the
 *  same material. Also, it *doesn't* recompute bounds.
 *
 *  \param prims the indices of the primitives to keep
 *  \param output a bare SubMeshGeometry to output to
 */
// This would be nice to put into SubMeshGeometry directly, but right now it
// doesn't handle all cases well enough to do that -- multiple materials,
// animations, etc.
void copySubset(const SubMeshGeometry& orig, const std::vector<int>& prims, SubMeshGeometry* output) {
    // Make sure we have a fresh start
    *output = SubMeshGeometry();
    output->name = orig.name;
    // Initialize texUVs for new mesh. Faster to initialize once here than check
    // every time through one of the data copying loops belo
    for(std::vector<SubMeshGeometry::TextureSet>::const_iterator tex_set_it = orig.texUVs.begin(); tex_set_it != orig.texUVs.end(); tex_set_it++) {
        output->texUVs.push_back(SubMeshGeometry::TextureSet());
        output->texUVs.back().stride = tex_set_it->stride;
    }

    // Keep track of which data is referenced
    std::vector<bool> referenced_indices(orig.positions.size(), false);

    // Iterate through all copied prims, marking indices as used
    for(std::vector<int>::const_iterator prim_it = prims.begin(); prim_it != prims.end(); prim_it++) {
        const SubMeshGeometry::Primitive& prim = orig.primitives[*prim_it];
        for(std::vector<unsigned short>::const_iterator ind_it = prim.indices.begin(); ind_it != prim.indices.end(); ind_it++)
            referenced_indices[*ind_it] = true;
    }

    // With them all marked, form a map to translate from old indices -> new
    // indices. Copy data over as we go.
    std::map<unsigned short, unsigned short> index_map;
    uint new_index_source = 0;
    for(int orig_index = 0; orig_index < (int)referenced_indices.size(); orig_index++) {
        if (referenced_indices[orig_index] == false) continue;
        index_map[orig_index] = new_index_source;
        new_index_source++;

        output->positions.push_back( orig.positions[orig_index] );
        if ((int)orig.normals.size() > orig_index)
            output->normals.push_back( orig.normals[orig_index] );
        if ((int)orig.tangents.size() > orig_index)
            output->tangents.push_back( orig.tangents[orig_index] );
        if ((int)orig.colors.size() > orig_index)
            output->colors.push_back( orig.colors[orig_index] );
        for(int tex_idx = 0; tex_idx < (int)orig.texUVs.size(); tex_idx++) {
            for(int stride_i = 0; stride_i < (int)orig.texUVs[tex_idx].stride; stride_i++)
                output->texUVs[tex_idx].uvs.push_back(
                    orig.texUVs[tex_idx].uvs[orig_index*orig.texUVs[tex_idx].stride + stride_i]
                );
        }
    }

    // Copy primitives over, adjusting indices
    for(std::vector<int>::const_iterator prim_it = prims.begin(); prim_it != prims.end(); prim_it++) {
        output->primitives.push_back(SubMeshGeometry::Primitive());
        const SubMeshGeometry::Primitive& orig_prim = orig.primitives[*prim_it];
        SubMeshGeometry::Primitive& new_prim = output->primitives.back();
        // NOTE: This is a special case for the transformation we want -- there
        // should only be one material so they all get mapped to 0.
        new_prim.materialId = 0;
        // Resize appropriately and copy new indices
        new_prim.indices.resize(orig_prim.indices.size());
        for(int ind = 0; ind < (int)orig_prim.indices.size(); ind++)
            new_prim.indices[ind] = index_map[ orig_prim.indices[ind] ];
    }

    // Copy animations
    for(SkinControllerList::const_iterator skin_it = orig.skinControllers.begin(); skin_it != orig.skinControllers.end(); skin_it++) {
        const SkinController& orig_skin = *skin_it;
        output->skinControllers.push_back(SkinController());
        SkinController& new_skin = output->skinControllers.back();

        // Some things aren't affected by the vertex data reduction
        new_skin.joints = orig_skin.joints;
        new_skin.bindShapeMatrix = orig_skin.bindShapeMatrix;
        new_skin.inverseBindMatrices = orig_skin.inverseBindMatrices;

        // weightStartIndices, weights, and jointIndices need to be
        // decimated based on the reduced set of vertices
        for(int orig_vert_idx = 0; orig_vert_idx < (int)referenced_indices.size(); orig_vert_idx++) {
            if (referenced_indices[orig_vert_idx] == false) continue;

            new_skin.weightStartIndices.push_back( new_skin.weights.size() );
            for(int influence_idx = orig_skin.weightStartIndices[orig_vert_idx];
                influence_idx < (int)orig_skin.weightStartIndices[orig_vert_idx+1];
                influence_idx++) {
                new_skin.weights.push_back( orig_skin.weights[influence_idx] );
                new_skin.jointIndices.push_back( orig_skin.jointIndices[influence_idx] );
            }
        }
        // One last entry in weightStartIndices because the extra
        // entry allows simple subtraction to determine #influences
        new_skin.weightStartIndices.push_back( new_skin.weights.size() );
    }
}

} // namespace

FilterDataPtr SingleMaterialGeometryFilter::apply(FilterDataPtr input) {
    for(FilterData::const_iterator md_it = input->begin(); md_it != input->end(); md_it++) {
        VisualPtr vis = *md_it;
        // Meshdata only currently
        MeshdataPtr md( std::tr1::dynamic_pointer_cast<Meshdata>(vis) );
        if (!md) continue;

        // Our approach is to run through all SubMeshGeometries generating
        // versions that are split. By maintaining a map from old indices to a
        // list of new indices, we can then run through all GeometryInstances,
        // duplicating them for each part of the original instance.

        // This map stores geometryIndex -> list of new geometry indices,
        // allowing the old instances to be split into a set of new instances
        typedef std::map<uint32, std::vector<uint32> > OldToNewIndexMap;
        OldToNewIndexMap new_geo_indices;

        // Our output should be a new set of SubMeshGeometries and a new set of
        // GeometryInstances referring to them.
        SubMeshGeometryList new_geometry;
        GeometryInstanceList new_instances;

        for(uint32 geo_idx = 0; geo_idx < md->geometry.size(); geo_idx++) {
            SubMeshGeometry& geo = md->geometry[geo_idx];

            // This mesh needs to be split into several new meshes, by
            // material. First, collect the primitives to be put under the copy
            // for each material.
            typedef std::map<SubMeshGeometry::Primitive::MaterialId, std::vector<int> > SingleMatPrimSetMap;
            SingleMatPrimSetMap new_meshes_prims;
            for(uint32 pi = 0; pi < geo.primitives.size(); pi++) {
                SubMeshGeometry::Primitive& prim = geo.primitives[pi];
                // Add this primitive
                new_meshes_prims[prim.materialId].push_back(pi);
            }

            // Then copy the submesh, using only the primitives for each item.
            typedef std::map<SubMeshGeometry::Primitive::MaterialId, SubMeshGeometry> SingleMatMeshMap;
            SingleMatMeshMap new_meshes;
            for(SingleMatPrimSetMap::iterator mat_it = new_meshes_prims.begin(); mat_it != new_meshes_prims.end(); mat_it++)
                copySubset(geo, mat_it->second, &new_meshes[mat_it->first]);
            new_meshes_prims.clear();

            // Recompute summary info for these new submeshes, add them to the
            // new set, and store their indices for use by the instance
            // geometries
            typedef std::map<SubMeshGeometry::Primitive::MaterialId, uint32> NewSubMeshIndexMap;
            NewSubMeshIndexMap new_indices_by_material;
            for(SingleMatMeshMap::iterator nm_it = new_meshes.begin(); nm_it != new_meshes.end(); nm_it++) {
                nm_it->second.recomputeBounds();
                uint32 new_index = new_geometry.size();
                new_geometry.push_back(nm_it->second);
                new_indices_by_material[nm_it->first] = new_index;
            }

            // Now, run through and find GeometryInstances which are using the
            // original mesh and make new ones using all the split ones
            for(uint32 ii = 0; ii < md->instances.size(); ii++) {
                GeometryInstance& geo_inst = md->instances[ii];
                if (geo_inst.geometryIndex != geo_idx) continue;

                for(NewSubMeshIndexMap::iterator sm_it = new_indices_by_material.begin(); sm_it != new_indices_by_material.end(); sm_it++) {
                    new_instances.push_back(geo_inst);
                    // Point to new index
                    new_instances.back().geometryIndex = sm_it->second;
                    // Reset material binding map, using only the material bound
                    // for this material from the earlier version.
                    new_instances.back().materialBindingMap.clear();
                    new_instances.back().materialBindingMap[0] = geo_inst.materialBindingMap[sm_it->first];
                }
            }
        }

        // After all the translation, just swapping out the list of
        // SubMeshGeometries and GeometryInstances should be safe
        md->geometry = new_geometry;
        md->instances = new_instances;
    }

    return input;
}

} // namespace Mesh
} // namespace Sirikata
<|endoftext|>


<commit_before>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/kernels/sendrecv_ops.h"

#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/logging.h"

namespace tensorflow {

static string GetRendezvousKeyPrefix(const string& send_device,
                                     const string& recv_device,
                                     const uint64 send_device_incarnation,
                                     const string& tensor_name) {
  return strings::StrCat(send_device, ";",
                         strings::FpToString(send_device_incarnation), ";",
                         recv_device, ";", tensor_name);
}

static void GetRendezvousKey(const string& key_prefix,
                             const FrameAndIter& frame_iter, string* key) {
  key->clear();
  strings::StrAppend(key, key_prefix, ";", frame_iter.frame_id, ":",
                     frame_iter.iter_id);
}

static FrameAndIter GetFrameAndIter(OpKernelContext* ctx,
                                    bool hostmem_sendrecv) {
  if (hostmem_sendrecv && ctx->call_frame() != nullptr) {
    // Host memory send/recv pairs are added by
    // common_runtime/memory_types.cc.  When the pair of nodes are
    // added inside a function, we need to use the function call frame
    // to formulate the unique rendezvous key.
    return FrameAndIter(reinterpret_cast<uint64>(ctx->call_frame()), 0);
  } else {
    return ctx->frame_iter();
  }
}

SendOp::SendOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
  string send_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("send_device", &send_device));
  string recv_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("recv_device", &recv_device));
  uint64 send_device_incarnation;
  OP_REQUIRES_OK(
      ctx, ctx->GetAttr("send_device_incarnation",
                        reinterpret_cast<int64*>(&send_device_incarnation)));
  string tensor_name;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("tensor_name", &tensor_name));
  key_prefix_ = GetRendezvousKeyPrefix(send_device, recv_device,
                                       send_device_incarnation, tensor_name);
  // The vast majority of Send nodes are outside any loop context, so
  // proactively cache the rendezvous key for the top-level.
  GetRendezvousKey(key_prefix_, {0, 0}, &parsed_key_.buf_);
  OP_REQUIRES_OK(ctx, Rendezvous::ParseKey(parsed_key_.buf_, &parsed_key_));
  if (!ctx->GetAttr("_hostmem_sendrecv", &hostmem_sendrecv_).ok()) {
    hostmem_sendrecv_ = false;
  }
}

void SendOp::Compute(OpKernelContext* ctx) {
  OP_REQUIRES(
      ctx, ctx->rendezvous() != nullptr,
      errors::Internal("Op kernel context needs to provide a rendezvous."));

  // The device context may be passed between the Send/Recv
  // boundary, so that the device context used to produce the Tensor
  // is used when performing the copy on the recv side (which may be
  // a different device).
  Rendezvous::Args args;
  args.device_context = ctx->op_device_context();
  args.alloc_attrs = ctx->input_alloc_attr(0);

  FrameAndIter frame_iter = GetFrameAndIter(ctx, hostmem_sendrecv_);
  if (frame_iter == FrameAndIter(0, 0)) {
    // Use the cached rendezvous key.
    VLOG(2) << "Send " << parsed_key_.buf_;
    OP_REQUIRES_OK(ctx,
                   ctx->rendezvous()->Send(parsed_key_, args, ctx->input(0),
                                           ctx->is_input_dead()));
  } else {
    Rendezvous::ParsedKey in_loop_parsed;
    GetRendezvousKey(key_prefix_, frame_iter, &in_loop_parsed.buf_);
    VLOG(2) << "Send " << in_loop_parsed.buf_;
    OP_REQUIRES_OK(ctx,
                   Rendezvous::ParseKey(in_loop_parsed.buf_, &in_loop_parsed));

    OP_REQUIRES_OK(ctx,
                   ctx->rendezvous()->Send(in_loop_parsed, args, ctx->input(0),
                                           ctx->is_input_dead()));
  }
}

REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_CPU), SendOp);
REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_GPU), SendOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_SYCL), SendOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostSend").Device(DEVICE_SYCL).HostMemory("tensor"), SendOp);
#endif // TENSORFLOW_USE_SYCL

REGISTER_KERNEL_BUILDER(Name("_HostSend").Device(DEVICE_CPU), SendOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostSend").Device(DEVICE_GPU).HostMemory("tensor"), SendOp);

RecvOp::RecvOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {
  string send_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("send_device", &send_device));
  string recv_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("recv_device", &recv_device));
  uint64 send_device_incarnation;
  OP_REQUIRES_OK(
      ctx, ctx->GetAttr("send_device_incarnation",
                        reinterpret_cast<int64*>(&send_device_incarnation)));
  string tensor_name;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("tensor_name", &tensor_name));
  key_prefix_ = GetRendezvousKeyPrefix(send_device, recv_device,
                                       send_device_incarnation, tensor_name);
  // The vast majority of Recv nodes are outside any loop context, so
  // proactively cache the rendezvous key for the top-level.
  GetRendezvousKey(key_prefix_, {0, 0}, &parsed_key_.buf_);
  OP_REQUIRES_OK(ctx, Rendezvous::ParseKey(parsed_key_.buf_, &parsed_key_));
  if (!ctx->GetAttr("_hostmem_sendrecv", &hostmem_sendrecv_).ok()) {
    hostmem_sendrecv_ = false;
  }
}

void RecvOp::ComputeAsync(OpKernelContext* ctx, DoneCallback done) {
  OP_REQUIRES(
      ctx, ctx->rendezvous() != nullptr,
      errors::Internal("Op kernel context needs to provide a rendezvous."));

  Rendezvous::Args args;
  args.device_context = ctx->op_device_context();
  args.alloc_attrs = ctx->output_alloc_attr(0);
  using namespace std::placeholders;
  Rendezvous::DoneCallback done_cb = std::bind(
      [ctx](DoneCallback done,
            // Begin unbound arguments.
            const Status& s, const Rendezvous::Args& send_args,
            const Rendezvous::Args& recv_args, const Tensor& val,
            bool is_dead) {
        ctx->SetStatus(s);
        if (s.ok()) {
          // 'ctx' allocates the output tensor of the expected type.
          // The runtime checks whether the tensor received here is
          // the same type.
          if (!is_dead) {
            ctx->set_output(0, val);
          }
          *ctx->is_output_dead() = is_dead;
        }
        done();
      },
      std::move(done), _1, _2, _3, _4, _5);

  FrameAndIter frame_iter = GetFrameAndIter(ctx, hostmem_sendrecv_);
  if (frame_iter == FrameAndIter(0, 0)) {
    VLOG(2) << "Recv " << parsed_key_.buf_;
    ctx->rendezvous()->RecvAsync(parsed_key_, args, std::move(done_cb));
  } else {
    Rendezvous::ParsedKey in_loop_parsed;
    GetRendezvousKey(key_prefix_, frame_iter, &in_loop_parsed.buf_);
    VLOG(2) << "Recv " << in_loop_parsed.buf_;
    OP_REQUIRES_OK_ASYNC(
        ctx, Rendezvous::ParseKey(in_loop_parsed.buf_, &in_loop_parsed), done);

    ctx->rendezvous()->RecvAsync(in_loop_parsed, args, std::move(done_cb));
  }
}

REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_CPU), RecvOp);
REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_GPU), RecvOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_SYCL), RecvOp);
#endif // TENSORFLOW_USE_SYCL

REGISTER_KERNEL_BUILDER(Name("_HostRecv").Device(DEVICE_CPU), RecvOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostRecv").Device(DEVICE_GPU).HostMemory("tensor"), RecvOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(
    Name("_HostRecv").Device(DEVICE_SYCL).HostMemory("tensor"), RecvOp);
#endif // TENSORFLOW_USE_SYCL

}  // end namespace tensorflow
<commit_msg>Do not log a warning when `Rendezvous::Send()` fails in the Send op kernel.<commit_after>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/kernels/sendrecv_ops.h"

#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/logging.h"

namespace tensorflow {

static string GetRendezvousKeyPrefix(const string& send_device,
                                     const string& recv_device,
                                     const uint64 send_device_incarnation,
                                     const string& tensor_name) {
  return strings::StrCat(send_device, ";",
                         strings::FpToString(send_device_incarnation), ";",
                         recv_device, ";", tensor_name);
}

static void GetRendezvousKey(const string& key_prefix,
                             const FrameAndIter& frame_iter, string* key) {
  key->clear();
  strings::StrAppend(key, key_prefix, ";", frame_iter.frame_id, ":",
                     frame_iter.iter_id);
}

static FrameAndIter GetFrameAndIter(OpKernelContext* ctx,
                                    bool hostmem_sendrecv) {
  if (hostmem_sendrecv && ctx->call_frame() != nullptr) {
    // Host memory send/recv pairs are added by
    // common_runtime/memory_types.cc.  When the pair of nodes are
    // added inside a function, we need to use the function call frame
    // to formulate the unique rendezvous key.
    return FrameAndIter(reinterpret_cast<uint64>(ctx->call_frame()), 0);
  } else {
    return ctx->frame_iter();
  }
}

SendOp::SendOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
  string send_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("send_device", &send_device));
  string recv_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("recv_device", &recv_device));
  uint64 send_device_incarnation;
  OP_REQUIRES_OK(
      ctx, ctx->GetAttr("send_device_incarnation",
                        reinterpret_cast<int64*>(&send_device_incarnation)));
  string tensor_name;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("tensor_name", &tensor_name));
  key_prefix_ = GetRendezvousKeyPrefix(send_device, recv_device,
                                       send_device_incarnation, tensor_name);
  // The vast majority of Send nodes are outside any loop context, so
  // proactively cache the rendezvous key for the top-level.
  GetRendezvousKey(key_prefix_, {0, 0}, &parsed_key_.buf_);
  OP_REQUIRES_OK(ctx, Rendezvous::ParseKey(parsed_key_.buf_, &parsed_key_));
  if (!ctx->GetAttr("_hostmem_sendrecv", &hostmem_sendrecv_).ok()) {
    hostmem_sendrecv_ = false;
  }
}

void SendOp::Compute(OpKernelContext* ctx) {
  OP_REQUIRES(
      ctx, ctx->rendezvous() != nullptr,
      errors::Internal("Op kernel context needs to provide a rendezvous."));

  // The device context may be passed between the Send/Recv
  // boundary, so that the device context used to produce the Tensor
  // is used when performing the copy on the recv side (which may be
  // a different device).
  Rendezvous::Args args;
  args.device_context = ctx->op_device_context();
  args.alloc_attrs = ctx->input_alloc_attr(0);

  FrameAndIter frame_iter = GetFrameAndIter(ctx, hostmem_sendrecv_);
  if (frame_iter == FrameAndIter(0, 0)) {
    // Use the cached rendezvous key.
    VLOG(2) << "Send " << parsed_key_.buf_;
    ctx->SetStatus(ctx->rendezvous()->Send(parsed_key_, args, ctx->input(0),
                                           ctx->is_input_dead()));
    return;
  } else {
    Rendezvous::ParsedKey in_loop_parsed;
    GetRendezvousKey(key_prefix_, frame_iter, &in_loop_parsed.buf_);
    VLOG(2) << "Send " << in_loop_parsed.buf_;
    OP_REQUIRES_OK(ctx,
                   Rendezvous::ParseKey(in_loop_parsed.buf_, &in_loop_parsed));

    ctx->SetStatus(ctx->rendezvous()->Send(in_loop_parsed, args, ctx->input(0),
                                           ctx->is_input_dead()));
    return;
  }
}

REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_CPU), SendOp);
REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_GPU), SendOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name("_Send").Device(DEVICE_SYCL), SendOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostSend").Device(DEVICE_SYCL).HostMemory("tensor"), SendOp);
#endif // TENSORFLOW_USE_SYCL

REGISTER_KERNEL_BUILDER(Name("_HostSend").Device(DEVICE_CPU), SendOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostSend").Device(DEVICE_GPU).HostMemory("tensor"), SendOp);

RecvOp::RecvOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {
  string send_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("send_device", &send_device));
  string recv_device;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("recv_device", &recv_device));
  uint64 send_device_incarnation;
  OP_REQUIRES_OK(
      ctx, ctx->GetAttr("send_device_incarnation",
                        reinterpret_cast<int64*>(&send_device_incarnation)));
  string tensor_name;
  OP_REQUIRES_OK(ctx, ctx->GetAttr("tensor_name", &tensor_name));
  key_prefix_ = GetRendezvousKeyPrefix(send_device, recv_device,
                                       send_device_incarnation, tensor_name);
  // The vast majority of Recv nodes are outside any loop context, so
  // proactively cache the rendezvous key for the top-level.
  GetRendezvousKey(key_prefix_, {0, 0}, &parsed_key_.buf_);
  OP_REQUIRES_OK(ctx, Rendezvous::ParseKey(parsed_key_.buf_, &parsed_key_));
  if (!ctx->GetAttr("_hostmem_sendrecv", &hostmem_sendrecv_).ok()) {
    hostmem_sendrecv_ = false;
  }
}

void RecvOp::ComputeAsync(OpKernelContext* ctx, DoneCallback done) {
  OP_REQUIRES(
      ctx, ctx->rendezvous() != nullptr,
      errors::Internal("Op kernel context needs to provide a rendezvous."));

  Rendezvous::Args args;
  args.device_context = ctx->op_device_context();
  args.alloc_attrs = ctx->output_alloc_attr(0);
  using namespace std::placeholders;
  Rendezvous::DoneCallback done_cb = std::bind(
      [ctx](DoneCallback done,
            // Begin unbound arguments.
            const Status& s, const Rendezvous::Args& send_args,
            const Rendezvous::Args& recv_args, const Tensor& val,
            bool is_dead) {
        ctx->SetStatus(s);
        if (s.ok()) {
          // 'ctx' allocates the output tensor of the expected type.
          // The runtime checks whether the tensor received here is
          // the same type.
          if (!is_dead) {
            ctx->set_output(0, val);
          }
          *ctx->is_output_dead() = is_dead;
        }
        done();
      },
      std::move(done), _1, _2, _3, _4, _5);

  FrameAndIter frame_iter = GetFrameAndIter(ctx, hostmem_sendrecv_);
  if (frame_iter == FrameAndIter(0, 0)) {
    VLOG(2) << "Recv " << parsed_key_.buf_;
    ctx->rendezvous()->RecvAsync(parsed_key_, args, std::move(done_cb));
  } else {
    Rendezvous::ParsedKey in_loop_parsed;
    GetRendezvousKey(key_prefix_, frame_iter, &in_loop_parsed.buf_);
    VLOG(2) << "Recv " << in_loop_parsed.buf_;
    OP_REQUIRES_OK_ASYNC(
        ctx, Rendezvous::ParseKey(in_loop_parsed.buf_, &in_loop_parsed), done);

    ctx->rendezvous()->RecvAsync(in_loop_parsed, args, std::move(done_cb));
  }
}

REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_CPU), RecvOp);
REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_GPU), RecvOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name("_Recv").Device(DEVICE_SYCL), RecvOp);
#endif // TENSORFLOW_USE_SYCL

REGISTER_KERNEL_BUILDER(Name("_HostRecv").Device(DEVICE_CPU), RecvOp);
REGISTER_KERNEL_BUILDER(
    Name("_HostRecv").Device(DEVICE_GPU).HostMemory("tensor"), RecvOp);

#ifdef TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(
    Name("_HostRecv").Device(DEVICE_SYCL).HostMemory("tensor"), RecvOp);
#endif // TENSORFLOW_USE_SYCL

}  // end namespace tensorflow
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <tuple>
#include <iostream>
#include "common.hh"

namespace tree {
}

void test_tree() {
}
<commit_msg>:construction: chore(node): add base node for tree<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <tuple>
#include <iostream>
#include "common.hh"

namespace tree {

using ColorType = bool;
static constexpr ColorType kColorRed = false;
static constexpr ColorType kColorBlack = true;
static constexpr int kHeightMask = 0xff;

struct NodeBase;
using BasePtr       = NodeBase*;
using ConstBasePtr  = const NodeBase*;

struct NodeBase {
  BasePtr parent;
  BasePtr left;
  BasePtr right;

  static inline BasePtr minimum(BasePtr x) noexcept {
    while (x->left != nullptr)
      x = x->left;
    return x;
  }

  static inline ConstBasePtr minimum(ConstBasePtr x) noexcept {
    return minimum(const_cast<BasePtr>(x));
  }

  static inline BasePtr maximum(BasePtr x) noexcept {
    while (x->right != nullptr)
      x = x->right;
    return x;
  }

  static inline ConstBasePtr maximum(ConstBasePtr x) noexcept {
    return maximum(const_cast<BasePtr>(x));
  }

  static BasePtr successor(BasePtr x) noexcept {
    if (x->right != nullptr) {
      x = x->right;
      while (x->left != nullptr)
        x = x->left;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->right) {
        x = y;
        y = y->parent;
      }
      if (x->right != y)
        x = y;
    }
    return x;
  }

  static ConstBasePtr successor(ConstBasePtr x) noexcept {
    return successor(const_cast<BasePtr>(x));
  }

  static BasePtr predecessor(BasePtr x) noexcept {
    if (x->left != nullptr) {
      x = x->left;
      while (x->right != nullptr)
        x = x->right;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->left) {
        x = y;
        y = y->parent;
      }
      x = y;
    }
    return x;
  }

  static ConstBasePtr predecessor(ConstBasePtr x) noexcept {
    return predecessor(const_cast<BasePtr>(x));
  }
};

struct AVLNodeBase : public NodeBase {
  using Ptr = AVLNodeBase*;

  int height;

  inline int lheight() const noexcept { return left ? Ptr(left)->height : 0; }
  inline int rheight() const noexcept { return right ? Ptr(right)->height : 0; }
  inline void update_height() noexcept { height = Xt::max(lheight(), rheight()) + 1; }

  static BasePtr predecessor(BasePtr x) noexcept {
    return (Ptr(x)->height == kHeightMask && x->parent->parent == x)
      ?  x->right : NodeBase::predecessor(x);
  }

  static ConstBasePtr predecessor(ConstBasePtr x) noexcept {
    return predecessor(const_cast<BasePtr>(x));
  }
};

struct RBNodeBase : public NodeBase {
  using Ptr = RBNodeBase*;

  ColorType color;

  inline bool is_red() const noexcept { return color == kColorRed; }
  inline bool is_black() const noexcept { return color == kColorBlack; }
  inline void set_red() noexcept { color = kColorRed; }
  inline void set_black() noexcept { color = kColorBlack; }

  static BasePtr predecessor(BasePtr x) noexcept {
    return (Ptr(x)->is_red() && x->parent->parent == x)
      ? x->right : NodeBase::predecessor(x);
  }

  static ConstBasePtr predecessor(ConstBasePtr x) noexcept {
    return predecessor(const_cast<BasePtr>(x));
  }
};

}

void test_tree() {
}
<|endoftext|>


<commit_before>#include <iostream>
#include "3.cpp"

using namespace std;

int main()
{
    DoubleLinkedChain<int> ch;
    DoubleLinkedList<int> L1, L2;
    int a1[] = {1, 3, 5, 7, 9, 6};
    int a2[] = {3, 4, 8, 5, 7};

    for (size_t i = 0; i < 5; i++)
    {
        L1.insertEnd(a1[i]);
        L2.insertEnd(a2[i]);
    }

    L1.insertEnd(a1[5]);

    ch.join(L1, L2);

    DoubleListElement<int> *front = ch.getFrontPtr(), *pn = front->prev;
    cout << "First chain: (";

    while (front && front->prev == pn)
    {
        cout << front->data << " ";
        pn = front;
        front = front->next;
    }

    cout << ")" << endl;
    cout << "First link between chains: " << pn->data << " -> " <<
                                          front->data << endl;
    DoubleListElement<int> *back = ch.getBackPtr();
    pn = back->next;
    cout << "Second chain (reversed): (";

    while (back && back->next == pn)
    {
        cout << back->data << " ";
        pn = back;
        back = back->prev;
    }

    cout << ")" << endl;
    cout << "Second link between chains: " << pn->data << " -> " <<
                                            back->data << endl;

    cout << "Is joined: " << ch.isJoined() << endl;
    cout << "Sum: " << ch.sum() << endl;
    return 0;
}
<commit_msg>added missing header files<commit_after>#include <iostream>
#include "dllist.cpp"
#include "dlchain.cpp"
#include "3.cpp"

using namespace std;

int main()
{
    DoubleLinkedChain<int> ch;
    DoubleLinkedList<int> L1, L2;
    int a1[] = {1, 3, 5, 7, 9, 6};
    int a2[] = {3, 4, 8, 5, 7};

    for (size_t i = 0; i < 5; i++)
    {
        L1.insertEnd(a1[i]);
        L2.insertEnd(a2[i]);
    }

    L1.insertEnd(a1[5]);

    ch.join(L1, L2);

    DoubleListElement<int> *front = ch.getFrontPtr(), *pn = front->prev;
    cout << "First chain: (";

    while (front && front->prev == pn)
    {
        cout << front->data << " ";
        pn = front;
        front = front->next;
    }

    cout << ")" << endl;
    cout << "First link between chains: " << pn->data << " -> " <<
                                          front->data << endl;
    DoubleListElement<int> *back = ch.getBackPtr();
    pn = back->next;
    cout << "Second chain (reversed): (";

    while (back && back->next == pn)
    {
        cout << back->data << " ";
        pn = back;
        back = back->prev;
    }

    cout << ")" << endl;
    cout << "Second link between chains: " << pn->data << " -> " <<
                                            back->data << endl;

    cout << "Is joined: " << ch.isJoined() << endl;
    cout << "Sum: " << ch.sum() << endl;
    return 0;
}
<|endoftext|>