<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 "base/basictypes.h"
#include "base/command_line.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#endif
#include "base/strings/stringprintf.h"
#include "base/win/windows_version.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/feature_switch.h"
#include "chrome/common/extensions/features/base_feature_provider.h"
#include "chrome/common/extensions/features/complex_feature.h"
#include "chrome/common/extensions/features/simple_feature.h"
#include "chrome/test/base/test_switches.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/features/feature.h"

namespace {

const char kExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";

class TabCaptureApiTest : public ExtensionApiTest {
 public:
  TabCaptureApiTest() {}

  virtual void SetUp() OVERRIDE {
    // TODO(danakj): The GPU Video Decoder needs real GL bindings.
    // crbug.com/269087
    UseRealGLBindings();

    ExtensionApiTest::SetUp();
  }

  void AddExtensionToCommandLineWhitelist() {
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kWhitelistedExtensionID, kExtensionId);
  }
};

}  // namespace

// http://crbug.com/261493 and http://crbug.com/268644
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_AURA)
#define MAYBE_ApiTests DISABLED_ApiTests
#else
#define MAYBE_ApiTests ApiTests
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTests) {
#if defined(OS_WIN) && defined(USE_ASH)
  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    return;
#endif

#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "api_tests.html")) << message_;
}

// http://crbug.com/268644
#if defined(USE_AURA)
#define MAYBE_ApiTestsAudio DISABLED_ApiTestsAudio
#else
#define MAYBE_ApiTestsAudio ApiTestsAudio
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTestsAudio) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "api_tests_audio.html")) << message_;
}

// http://crbug.com/177163 and http://crbug.com/268644
#if defined(OS_WIN) && (!defined(NDEBUG) || defined(USE_AURA))
#define MAYBE_EndToEnd DISABLED_EndToEnd
#else
#define MAYBE_EndToEnd EndToEnd
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_EndToEnd) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif
#if defined(OS_MACOSX)
  // TODO(miu): Disabled for Mac OS X 10.6 due to timeout issues.
  // http://crbug.com/174640
  if (base::mac::IsOSSnowLeopard())
    return;
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "end_to_end.html")) << message_;
}

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_GetUserMediaTest DISABLED_GetUserMediaTest
#else
#define MAYBE_GetUserMediaTest GetUserMediaTest
#endif
// Test that we can't get tabCapture streams using GetUserMedia directly.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_GetUserMediaTest) {
  ExtensionTestMessageListener listener("ready", true);

  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "get_user_media_test.html")) << message_;

  EXPECT_TRUE(listener.WaitUntilSatisfied());

  content::OpenURLParams params(GURL("about:blank"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);

  content::RenderViewHost* const rvh = web_contents->GetRenderViewHost();
  int render_process_id = rvh->GetProcess()->GetID();
  int routing_id = rvh->GetRoutingID();

  listener.Reply(base::StringPrintf("%i:%i", render_process_id, routing_id));

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// http://crbug.com/177163
#if defined(OS_WIN)
#define MAYBE_ActiveTabPermission DISABLED_ActiveTabPermission
#else
#define MAYBE_ActiveTabPermission ActiveTabPermission
#endif
// Make sure tabCapture.capture only works if the tab has been granted
// permission via an extension icon click or the extension is whitelisted.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ActiveTabPermission) {
  ExtensionTestMessageListener before_open_tab("ready1", true);
  ExtensionTestMessageListener before_grant_permission("ready2", true);
  ExtensionTestMessageListener before_open_new_tab("ready3", true);
  ExtensionTestMessageListener before_whitelist_extension("ready4", true);

  ASSERT_TRUE(RunExtensionSubtest(
      "tab_capture/experimental", "active_tab_permission_test.html"))
          << message_;

  // Open a new tab and make sure capture is denied.
  EXPECT_TRUE(before_open_tab.WaitUntilSatisfied());
  content::OpenURLParams params(GURL("http://google.com"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);
  before_open_tab.Reply("");

  // Grant permission and make sure capture succeeds.
  EXPECT_TRUE(before_grant_permission.WaitUntilSatisfied());
  ExtensionService* extension_service =
      Profile::FromBrowserContext(web_contents->GetBrowserContext())
          ->GetExtensionService();
  const extensions::Extension* extension =
      extension_service->GetExtensionById(kExtensionId, false);
  extensions::TabHelper::FromWebContents(web_contents)
      ->active_tab_permission_granter()->GrantIfRequested(extension);
  before_grant_permission.Reply("");

  // Open a new tab and make sure capture is denied.
  EXPECT_TRUE(before_open_new_tab.WaitUntilSatisfied());
  browser()->OpenURL(params);
  before_open_new_tab.Reply("");

  // Add extension to whitelist and make sure capture succeeds.
  EXPECT_TRUE(before_whitelist_extension.WaitUntilSatisfied());
  AddExtensionToCommandLineWhitelist();
  before_whitelist_extension.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#elif defined(USE_AURA) || defined(OS_MACOSX)
// These don't always fire fullscreen events when run in tests. Tested manually.
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#elif defined(OS_LINUX)
// Flaky to get out of fullscreen in tests. Tested manually.
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#else
#define MAYBE_FullscreenEvents FullscreenEvents
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_FullscreenEvents) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();

  content::OpenURLParams params(GURL("chrome://version"),
                                content::Referrer(),
                                CURRENT_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);

  ExtensionTestMessageListener listeners_setup("ready1", true);
  ExtensionTestMessageListener fullscreen_entered("ready2", true);

  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "fullscreen_test.html")) << message_;
  EXPECT_TRUE(listeners_setup.WaitUntilSatisfied());

  // Toggle fullscreen after setting up listeners.
  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
                                                                 true);
  listeners_setup.Reply("");

  // Toggle again after JS should have the event.
  EXPECT_TRUE(fullscreen_entered.WaitUntilSatisfied());
  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
                                                                 false);
  fullscreen_entered.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Times out on Win dbg bots: http://crbug.com/177163
// #if defined(OS_WIN) && !defined(NDEBUG)
// Times out on all Win bots: http://crbug.com/294431
#if defined(OS_WIN)
#define MAYBE_GrantForChromePages DISABLED_GrantForChromePages
#else
#define MAYBE_GrantForChromePages GrantForChromePages
#endif
// Make sure tabCapture API can be granted for Chrome:// pages.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_GrantForChromePages) {
  ExtensionTestMessageListener before_open_tab("ready1", true);
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "active_tab_chrome_pages.html")) << message_;
  EXPECT_TRUE(before_open_tab.WaitUntilSatisfied());

  // Open a tab on a chrome:// page and make sure we can capture.
  content::OpenURLParams params(GURL("chrome://version"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);
  ExtensionService* extension_service =
      Profile::FromBrowserContext(web_contents->GetBrowserContext())
          ->GetExtensionService();
  extensions::TabHelper::FromWebContents(web_contents)
      ->active_tab_permission_granter()->GrantIfRequested(
            extension_service->GetExtensionById(kExtensionId, false));
  before_open_tab.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

#if defined(OS_WIN)
#define MAYBE_CaptureInSplitIncognitoMode DISABLED_CaptureInSplitIncognitoMode
#else
#define MAYBE_CaptureInSplitIncognitoMode CaptureInSplitIncognitoMode
#endif
// Test that a tab can be captured in split incognito mode.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_CaptureInSplitIncognitoMode) {
  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "incognito.html",
                                  kFlagEnableIncognito | kFlagUseIncognito))
      << message_;
}

#if defined(OS_WIN)
#define MAYBE_Constraints DISABLED_Constraints
#else
#define MAYBE_Constraints Constraints
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_Constraints) {
  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "constraints.html")) << message_;
}
<commit_msg>Re-enable TabCaptureApiTest.ApiTests for Linux.<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 "base/basictypes.h"
#include "base/command_line.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#endif
#include "base/strings/stringprintf.h"
#include "base/win/windows_version.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/feature_switch.h"
#include "chrome/common/extensions/features/base_feature_provider.h"
#include "chrome/common/extensions/features/complex_feature.h"
#include "chrome/common/extensions/features/simple_feature.h"
#include "chrome/test/base/test_switches.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/features/feature.h"

namespace {

const char kExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";

class TabCaptureApiTest : public ExtensionApiTest {
 public:
  TabCaptureApiTest() {}

  virtual void SetUp() OVERRIDE {
    // TODO(danakj): The GPU Video Decoder needs real GL bindings.
    // crbug.com/269087
    UseRealGLBindings();

    ExtensionApiTest::SetUp();
  }

  void AddExtensionToCommandLineWhitelist() {
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kWhitelistedExtensionID, kExtensionId);
  }
};

}  // namespace

// http://crbug.com/261493 and http://crbug.com/268644
#if defined(OS_CHROMEOS) || defined(USE_AURA)
#define MAYBE_ApiTests DISABLED_ApiTests
#else
#define MAYBE_ApiTests ApiTests
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTests) {
#if defined(OS_WIN) && defined(USE_ASH)
  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    return;
#endif

#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "api_tests.html")) << message_;
}

// http://crbug.com/268644
#if defined(USE_AURA)
#define MAYBE_ApiTestsAudio DISABLED_ApiTestsAudio
#else
#define MAYBE_ApiTestsAudio ApiTestsAudio
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ApiTestsAudio) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "api_tests_audio.html")) << message_;
}

// http://crbug.com/177163 and http://crbug.com/268644
#if defined(OS_WIN) && (!defined(NDEBUG) || defined(USE_AURA))
#define MAYBE_EndToEnd DISABLED_EndToEnd
#else
#define MAYBE_EndToEnd EndToEnd
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_EndToEnd) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif
#if defined(OS_MACOSX)
  // TODO(miu): Disabled for Mac OS X 10.6 due to timeout issues.
  // http://crbug.com/174640
  if (base::mac::IsOSSnowLeopard())
    return;
#endif

  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "end_to_end.html")) << message_;
}

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_GetUserMediaTest DISABLED_GetUserMediaTest
#else
#define MAYBE_GetUserMediaTest GetUserMediaTest
#endif
// Test that we can't get tabCapture streams using GetUserMedia directly.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_GetUserMediaTest) {
  ExtensionTestMessageListener listener("ready", true);

  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "get_user_media_test.html")) << message_;

  EXPECT_TRUE(listener.WaitUntilSatisfied());

  content::OpenURLParams params(GURL("about:blank"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);

  content::RenderViewHost* const rvh = web_contents->GetRenderViewHost();
  int render_process_id = rvh->GetProcess()->GetID();
  int routing_id = rvh->GetRoutingID();

  listener.Reply(base::StringPrintf("%i:%i", render_process_id, routing_id));

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// http://crbug.com/177163
#if defined(OS_WIN)
#define MAYBE_ActiveTabPermission DISABLED_ActiveTabPermission
#else
#define MAYBE_ActiveTabPermission ActiveTabPermission
#endif
// Make sure tabCapture.capture only works if the tab has been granted
// permission via an extension icon click or the extension is whitelisted.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_ActiveTabPermission) {
  ExtensionTestMessageListener before_open_tab("ready1", true);
  ExtensionTestMessageListener before_grant_permission("ready2", true);
  ExtensionTestMessageListener before_open_new_tab("ready3", true);
  ExtensionTestMessageListener before_whitelist_extension("ready4", true);

  ASSERT_TRUE(RunExtensionSubtest(
      "tab_capture/experimental", "active_tab_permission_test.html"))
          << message_;

  // Open a new tab and make sure capture is denied.
  EXPECT_TRUE(before_open_tab.WaitUntilSatisfied());
  content::OpenURLParams params(GURL("http://google.com"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);
  before_open_tab.Reply("");

  // Grant permission and make sure capture succeeds.
  EXPECT_TRUE(before_grant_permission.WaitUntilSatisfied());
  ExtensionService* extension_service =
      Profile::FromBrowserContext(web_contents->GetBrowserContext())
          ->GetExtensionService();
  const extensions::Extension* extension =
      extension_service->GetExtensionById(kExtensionId, false);
  extensions::TabHelper::FromWebContents(web_contents)
      ->active_tab_permission_granter()->GrantIfRequested(extension);
  before_grant_permission.Reply("");

  // Open a new tab and make sure capture is denied.
  EXPECT_TRUE(before_open_new_tab.WaitUntilSatisfied());
  browser()->OpenURL(params);
  before_open_new_tab.Reply("");

  // Add extension to whitelist and make sure capture succeeds.
  EXPECT_TRUE(before_whitelist_extension.WaitUntilSatisfied());
  AddExtensionToCommandLineWhitelist();
  before_whitelist_extension.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// http://crbug.com/177163
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#elif defined(USE_AURA) || defined(OS_MACOSX)
// These don't always fire fullscreen events when run in tests. Tested manually.
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#elif defined(OS_LINUX)
// Flaky to get out of fullscreen in tests. Tested manually.
#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
#else
#define MAYBE_FullscreenEvents FullscreenEvents
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_FullscreenEvents) {
#if defined(OS_WIN)
  // TODO(justinlin): Disabled for WinXP due to timeout issues.
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    return;
  }
#endif

  AddExtensionToCommandLineWhitelist();

  content::OpenURLParams params(GURL("chrome://version"),
                                content::Referrer(),
                                CURRENT_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);

  ExtensionTestMessageListener listeners_setup("ready1", true);
  ExtensionTestMessageListener fullscreen_entered("ready2", true);

  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "fullscreen_test.html")) << message_;
  EXPECT_TRUE(listeners_setup.WaitUntilSatisfied());

  // Toggle fullscreen after setting up listeners.
  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
                                                                 true);
  listeners_setup.Reply("");

  // Toggle again after JS should have the event.
  EXPECT_TRUE(fullscreen_entered.WaitUntilSatisfied());
  browser()->fullscreen_controller()->ToggleFullscreenModeForTab(web_contents,
                                                                 false);
  fullscreen_entered.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Times out on Win dbg bots: http://crbug.com/177163
// #if defined(OS_WIN) && !defined(NDEBUG)
// Times out on all Win bots: http://crbug.com/294431
#if defined(OS_WIN)
#define MAYBE_GrantForChromePages DISABLED_GrantForChromePages
#else
#define MAYBE_GrantForChromePages GrantForChromePages
#endif
// Make sure tabCapture API can be granted for Chrome:// pages.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_GrantForChromePages) {
  ExtensionTestMessageListener before_open_tab("ready1", true);
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "active_tab_chrome_pages.html")) << message_;
  EXPECT_TRUE(before_open_tab.WaitUntilSatisfied());

  // Open a tab on a chrome:// page and make sure we can capture.
  content::OpenURLParams params(GURL("chrome://version"), content::Referrer(),
                                NEW_FOREGROUND_TAB,
                                content::PAGE_TRANSITION_LINK, false);
  content::WebContents* web_contents = browser()->OpenURL(params);
  ExtensionService* extension_service =
      Profile::FromBrowserContext(web_contents->GetBrowserContext())
          ->GetExtensionService();
  extensions::TabHelper::FromWebContents(web_contents)
      ->active_tab_permission_granter()->GrantIfRequested(
            extension_service->GetExtensionById(kExtensionId, false));
  before_open_tab.Reply("");

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

#if defined(OS_WIN)
#define MAYBE_CaptureInSplitIncognitoMode DISABLED_CaptureInSplitIncognitoMode
#else
#define MAYBE_CaptureInSplitIncognitoMode CaptureInSplitIncognitoMode
#endif
// Test that a tab can be captured in split incognito mode.
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_CaptureInSplitIncognitoMode) {
  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "incognito.html",
                                  kFlagEnableIncognito | kFlagUseIncognito))
      << message_;
}

#if defined(OS_WIN)
#define MAYBE_Constraints DISABLED_Constraints
#else
#define MAYBE_Constraints Constraints
#endif
IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_Constraints) {
  AddExtensionToCommandLineWhitelist();
  ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental",
                                  "constraints.html")) << message_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"

class NotificationsPermissionTest : public UITest {
 public:
  NotificationsPermissionTest() {
    dom_automation_enabled_ = true;
    show_window_ = true;
  }
};

// Flaky, http://crbug.com/62311.
TEST_F(NotificationsPermissionTest, FLAKY_TestUserGestureInfobar) {
  net::TestServer test_server(net::TestServer::TYPE_HTTP,
                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(test_server.Start());

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_refptr<TabProxy> tab(browser->GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server.GetURL(
                "files/notifications/notifications_request_function.html")));
  WaitUntilTabCount(1);

  // Request permission by calling request() while eval'ing an inline script;
  // That's considered a user gesture to webkit, and should produce an infobar.
  bool result;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(
      L"",
      L"window.domAutomationController.send(request());",
      &result));
  EXPECT_TRUE(result);

  EXPECT_TRUE(tab->WaitForInfoBarCount(1));
}

// Flaky, http://crbug.com/62311.
TEST_F(NotificationsPermissionTest, FLAKY_TestNoUserGestureInfobar) {
  net::TestServer test_server(net::TestServer::TYPE_HTTP,
                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(test_server.Start());

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_refptr<TabProxy> tab(browser->GetActiveTab());
  ASSERT_TRUE(tab.get());

  // Load a page which just does a request; no user gesture should result
  // in no infobar.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server.GetURL(
                "files/notifications/notifications_request_inline.html")));
  WaitUntilTabCount(1);

  size_t info_bar_count;
  ASSERT_TRUE(tab->GetInfoBarCount(&info_bar_count));
  EXPECT_EQ(0U, info_bar_count);
}
<commit_msg>Disable test that's timing out BUG=74428 TEST=none Review URL: http://codereview.chromium.org/6598038<commit_after>// Copyright (c) 2011 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/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"

class NotificationsPermissionTest : public UITest {
 public:
  NotificationsPermissionTest() {
    dom_automation_enabled_ = true;
    show_window_ = true;
  }
};

// Flaky, http://crbug.com/62311 and http://crbug.com/74428.
TEST_F(NotificationsPermissionTest, DISABLED_TestUserGestureInfobar) {
  net::TestServer test_server(net::TestServer::TYPE_HTTP,
                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(test_server.Start());

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_refptr<TabProxy> tab(browser->GetActiveTab());
  ASSERT_TRUE(tab.get());
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server.GetURL(
                "files/notifications/notifications_request_function.html")));
  WaitUntilTabCount(1);

  // Request permission by calling request() while eval'ing an inline script;
  // That's considered a user gesture to webkit, and should produce an infobar.
  bool result;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(
      L"",
      L"window.domAutomationController.send(request());",
      &result));
  EXPECT_TRUE(result);

  EXPECT_TRUE(tab->WaitForInfoBarCount(1));
}

// Flaky, http://crbug.com/62311.
TEST_F(NotificationsPermissionTest, FLAKY_TestNoUserGestureInfobar) {
  net::TestServer test_server(net::TestServer::TYPE_HTTP,
                              FilePath(FILE_PATH_LITERAL("chrome/test/data")));
  ASSERT_TRUE(test_server.Start());

  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());
  scoped_refptr<TabProxy> tab(browser->GetActiveTab());
  ASSERT_TRUE(tab.get());

  // Load a page which just does a request; no user gesture should result
  // in no infobar.
  ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS,
            tab->NavigateToURL(test_server.GetURL(
                "files/notifications/notifications_request_inline.html")));
  WaitUntilTabCount(1);

  size_t info_bar_count;
  ASSERT_TRUE(tab->GetInfoBarCount(&info_bar_count));
  EXPECT_EQ(0U, info_bar_count);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2015 John Connor (BM-NC49AxAjcqVcF5jNPu85Rb8MJ2d9JqZt)
 *
 * This file is part of vanillacoin.
 *
 * vanillacoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <coin/globals.hpp>
#include <coin/stack_impl.hpp>
#include <coin/zerotime.hpp>
#include <coin/zerotime_manager.hpp>

using namespace coin;

zerotime_manager::zerotime_manager(
    boost::asio::io_service & ios, boost::asio::strand & s, stack_impl & owner
    )
    : io_service_(ios)
    , strand_(s)
    , stack_impl_(owner)
    , timer_(ios)
{
    // ...
}

void zerotime_manager::start()
{
    /**
     * Start the timer.
     */
    do_tick(60);
}

void zerotime_manager::stop()
{
    timer_.cancel();
}

void zerotime_manager::probe_for_answers(
    const sha256 & hash_tx,
    const std::vector<transaction_in> & transactions_in
    )
{
    if (globals::instance().is_zerotime_enabled())
    {
        if (m_questions.count(hash_tx) == 0)
        {
            #warning :TODO:

            // Prepare:
            // :TODO: m_questions[hash_tx] = zerotime_question(transactions_in);
            // :TODO: 6 blocks = 20 mins = 1200 seconds
            // :TODO: m_qa_expire_times[hash_tx] = std::time(0) + (20 * 60);

            // Probe:
            // :TODO: auto addrs = stack_impl_.get_address_manager()->get_addr(8);
            // :TODO: m_questioned_tcp_endpoints[hash_tx].push_back(addrs[0]);

            // Listen:
            // :TODO: m_answers_tcp[ztanswer.hash_tx()].push_back(std::make_pair(ep, ztanswer));
        }
    }
}

void zerotime_manager::do_tick(const std::uint32_t & interval)
{
    auto self(shared_from_this());

    timer_.expires_from_now(std::chrono::seconds(interval));
    timer_.async_wait(strand_.wrap([this, self, interval]
        (boost::system::error_code ec)
    {
        if (ec)
        {
            // ...
        }
        else
        {
            if (globals::instance().is_zerotime_enabled())
            {
                /**
                 * Clear expired input locks.
                 */
                zerotime::instance().clear_expired_input_locks();
            }

            /**
             * Start the timer.
             */
            do_tick(60);
        }
    }));
}
<commit_msg>removed compile warning<commit_after>/*
 * Copyright (c) 2013-2015 John Connor (BM-NC49AxAjcqVcF5jNPu85Rb8MJ2d9JqZt)
 *
 * This file is part of vanillacoin.
 *
 * vanillacoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <coin/globals.hpp>
#include <coin/stack_impl.hpp>
#include <coin/zerotime.hpp>
#include <coin/zerotime_manager.hpp>

using namespace coin;

zerotime_manager::zerotime_manager(
    boost::asio::io_service & ios, boost::asio::strand & s, stack_impl & owner
    )
    : io_service_(ios)
    , strand_(s)
    , stack_impl_(owner)
    , timer_(ios)
{
    // ...
}

void zerotime_manager::start()
{
    /**
     * Start the timer.
     */
    do_tick(60);
}

void zerotime_manager::stop()
{
    timer_.cancel();
}

void zerotime_manager::probe_for_answers(
    const sha256 & hash_tx,
    const std::vector<transaction_in> & transactions_in
    )
{
    if (globals::instance().is_zerotime_enabled())
    {
        if (m_questions.count(hash_tx) == 0)
        {

        }
    }
}

void zerotime_manager::do_tick(const std::uint32_t & interval)
{
    auto self(shared_from_this());

    timer_.expires_from_now(std::chrono::seconds(interval));
    timer_.async_wait(strand_.wrap([this, self, interval]
        (boost::system::error_code ec)
    {
        if (ec)
        {
            // ...
        }
        else
        {
            if (globals::instance().is_zerotime_enabled())
            {
                /**
                 * Clear expired input locks.
                 */
                zerotime::instance().clear_expired_input_locks();
            }

            /**
             * Start the timer.
             */
            do_tick(60);
        }
    }));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */

#include <graphene/account_history/account_history_plugin.hpp>

#include <graphene/chain/impacted.hpp>

#include <graphene/chain/account_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/config.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>

#include <fc/smart_ref_impl.hpp>
#include <fc/thread/thread.hpp>

namespace graphene { namespace account_history {

namespace detail
{

class account_history_plugin_impl
{
   public:
      account_history_plugin_impl(account_history_plugin& _plugin)
         : _self( _plugin )
      { }
      virtual ~account_history_plugin_impl();

      /** this method is called as a callback after a block is applied
       * and will process/index all operations that were applied in the block.
       */
      void update_account_histories( const signed_block& b );

      graphene::chain::database& database()
      {
         return _self.database();
      }

      account_history_plugin& _self;
      flat_set<account_id_type> _tracked_accounts;
      bool _partial_operations = false;
      primary_index< operation_history_index >* _oho_index;
      uint64_t _max_ops_per_account = -1;
   private:
      /** add one history record, then check and remove the earliest history record */
      void add_account_history( const account_id_type account_id, const operation_history_id_type op_id );

};

account_history_plugin_impl::~account_history_plugin_impl()
{
   return;
}

void account_history_plugin_impl::update_account_histories( const signed_block& b )
{
   graphene::chain::database& db = database();
   const vector<optional< operation_history_object > >& hist = db.get_applied_operations();
   bool is_first = true;
   auto skip_oho_id = [&is_first,&db,this]() {
      if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
      {
         db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
         is_first = false;
      }
      else
         _oho_index->use_next_id();
   };

   for( const optional< operation_history_object >& o_op : hist )
   {
      optional<operation_history_object> oho;

      auto create_oho = [&]() {
         is_first = false;
         return optional<operation_history_object>( db.create<operation_history_object>( [&]( operation_history_object& h )
         {
            if( o_op.valid() )
            {
               h.op           = o_op->op;
               h.result       = o_op->result;
               h.block_num    = o_op->block_num;
               h.trx_in_block = o_op->trx_in_block;
               h.op_in_trx    = o_op->op_in_trx;
               h.virtual_op   = o_op->virtual_op;
            }
         } ) );
      };

      if( !o_op.valid() || ( _max_ops_per_account == 0 && _partial_operations ) )
      {
         // Note: the 2nd and 3rd checks above are for better performance, when the db is not clean,
         //       they will break consistency of account_stats.total_ops and removed_ops and most_recent_op
         skip_oho_id();
         continue;
      }
      else if( !_partial_operations )
         // add to the operation history index
         oho = create_oho();

      const operation_history_object& op = *o_op;

      // get the set of accounts this operation applies to
      flat_set<account_id_type> impacted;
      vector<authority> other;
      operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here

      if( op.op.which() == operation::tag< account_create_operation >::value )
         impacted.insert( op.result.get<object_id_type>() );
      else
         graphene::chain::operation_get_impacted_accounts( op.op, impacted );

      for( auto& a : other )
         for( auto& item : a.account_auths )
            impacted.insert( item.first );

      // be here, either _max_ops_per_account > 0, or _partial_operations == false, or both
      // if _partial_operations == false, oho should have been created above
      // so the only case should be checked here is:
      //    whether need to create oho if _max_ops_per_account > 0 and _partial_operations == true

      // for each operation this account applies to that is in the config link it into the history
      if( _tracked_accounts.size() == 0 ) // tracking all accounts
      {
         // if tracking all accounts, when impacted is not empty (although it will always be),
         //    still need to create oho if _max_ops_per_account > 0 and _partial_operations == true
         //    so always need to create oho if not done
         if (!impacted.empty() && !oho.valid()) { oho = create_oho(); }

         if( _max_ops_per_account > 0 )
         {
            // Note: the check above is for better performance, when the db is not clean,
            //       it breaks consistency of account_stats.total_ops and removed_ops and most_recent_op,
            //       but it ensures it's safe to remove old entries in add_account_history(...)
            for( auto& account_id : impacted )
            {
               // we don't do index_account_keys here anymore, because
               // that indexing now happens in observers' post_evaluate()

               // add history
               add_account_history( account_id, oho->id );
            }
         }
      }
      else // tracking a subset of accounts
      {
         // whether need to create oho if _max_ops_per_account > 0 and _partial_operations == true ?
         // the answer: only need to create oho if a tracked account is impacted and need to save history

         if( _max_ops_per_account > 0 )
         {
            // Note: the check above is for better performance, when the db is not clean,
            //       it breaks consistency of account_stats.total_ops and removed_ops and most_recent_op,
            //       but it ensures it's safe to remove old entries in add_account_history(...)
            for( auto account_id : _tracked_accounts )
            {
               if( impacted.find( account_id ) != impacted.end() )
               {
                  if (!oho.valid()) { oho = create_oho(); }
                  // add history
                  add_account_history( account_id, oho->id );
               }
            }
         }
      }
      if (_partial_operations && ! oho.valid())
         skip_oho_id();
   }
}

void account_history_plugin_impl::add_account_history( const account_id_type account_id, const operation_history_id_type op_id )
{
   graphene::chain::database& db = database();
   const auto& stats_obj = account_id(db).statistics(db);
   // add new entry
   const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){
       obj.operation_id = op_id;
       obj.account = account_id;
       obj.sequence = stats_obj.total_ops + 1;
       obj.next = stats_obj.most_recent_op;
   });
   db.modify( stats_obj, [&]( account_statistics_object& obj ){
       obj.most_recent_op = ath.id;
       obj.total_ops = ath.sequence;
   });
   // remove the earliest account history entry if too many
   // _max_ops_per_account is guaranteed to be non-zero outside
   if( stats_obj.total_ops - stats_obj.removed_ops > _max_ops_per_account )
   {
      // look for the earliest entry
      const auto& his_idx = db.get_index_type<account_transaction_history_index>();
      const auto& by_seq_idx = his_idx.indices().get<by_seq>();
      auto itr = by_seq_idx.lower_bound( boost::make_tuple( account_id, 0 ) );
      // make sure don't remove the one just added
      if( itr != by_seq_idx.end() && itr->account == account_id && itr->id != ath.id )
      {
         // if found, remove the entry, and adjust account stats object
         const auto remove_op_id = itr->operation_id;
         const auto itr_remove = itr;
         ++itr;
         db.remove( *itr_remove );
         db.modify( stats_obj, [&]( account_statistics_object& obj ){
             obj.removed_ops = obj.removed_ops + 1;
         });
         // modify previous node's next pointer
         // this should be always true, but just have a check here
         if( itr != by_seq_idx.end() && itr->account == account_id )
         {
            db.modify( *itr, [&]( account_transaction_history_object& obj ){
               obj.next = account_transaction_history_id_type();
            });
         }
         // else need to modify the head pointer, but it shouldn't be true

         // remove the operation history entry (1.11.x) if configured and no reference left
         if( _partial_operations )
         {
            // check for references
            const auto& by_opid_idx = his_idx.indices().get<by_opid>();
            if( by_opid_idx.find( remove_op_id ) == by_opid_idx.end() )
            {
               // if no reference, remove
               db.remove( remove_op_id(db) );
            }
         }
      }
   }
}

} // end namespace detail

account_history_plugin::account_history_plugin() :
   my( new detail::account_history_plugin_impl(*this) )
{
}

account_history_plugin::~account_history_plugin()
{
}

std::string account_history_plugin::plugin_name()const
{
   return "account_history";
}

void account_history_plugin::plugin_set_program_options(
   boost::program_options::options_description& cli,
   boost::program_options::options_description& cfg
   )
{
   cli.add_options()
         ("track-account", boost::program_options::value<std::vector<std::string>>()->composing()->multitoken(), "Account ID to track history for (may specify multiple times)")
         ("partial-operations", boost::program_options::value<bool>(), "Keep only those operations in memory that are related to account history tracking")
         ("max-ops-per-account", boost::program_options::value<uint32_t>(), "Maximum number of operations per account will be kept in memory")
         ;
   cfg.add(cli);
}

void account_history_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{
   database().applied_block.connect( [&]( const signed_block& b){ my->update_account_histories(b); } );
   my->_oho_index = database().add_index< primary_index< operation_history_index > >();
   database().add_index< primary_index< account_transaction_history_index > >();

   LOAD_VALUE_SET(options, "track-account", my->_tracked_accounts, graphene::chain::account_id_type);
   if (options.count("partial-operations")) {
       my->_partial_operations = options["partial-operations"].as<bool>();
   }
   if (options.count("max-ops-per-account")) {
       my->_max_ops_per_account = options["max-ops-per-account"].as<uint64_t>();
   }
}

void account_history_plugin::plugin_startup()
{
}

flat_set<account_id_type> account_history_plugin::tracked_accounts() const
{
   return my->_tracked_accounts;
}

} }
<commit_msg>Update max-ops-per-account program option to 64bit<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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.
 */

#include <graphene/account_history/account_history_plugin.hpp>

#include <graphene/chain/impacted.hpp>

#include <graphene/chain/account_evaluator.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/config.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/evaluator.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/transaction_evaluation_state.hpp>

#include <fc/smart_ref_impl.hpp>
#include <fc/thread/thread.hpp>

namespace graphene { namespace account_history {

namespace detail
{

class account_history_plugin_impl
{
   public:
      account_history_plugin_impl(account_history_plugin& _plugin)
         : _self( _plugin )
      { }
      virtual ~account_history_plugin_impl();

      /** this method is called as a callback after a block is applied
       * and will process/index all operations that were applied in the block.
       */
      void update_account_histories( const signed_block& b );

      graphene::chain::database& database()
      {
         return _self.database();
      }

      account_history_plugin& _self;
      flat_set<account_id_type> _tracked_accounts;
      bool _partial_operations = false;
      primary_index< operation_history_index >* _oho_index;
      uint64_t _max_ops_per_account = -1;
   private:
      /** add one history record, then check and remove the earliest history record */
      void add_account_history( const account_id_type account_id, const operation_history_id_type op_id );

};

account_history_plugin_impl::~account_history_plugin_impl()
{
   return;
}

void account_history_plugin_impl::update_account_histories( const signed_block& b )
{
   graphene::chain::database& db = database();
   const vector<optional< operation_history_object > >& hist = db.get_applied_operations();
   bool is_first = true;
   auto skip_oho_id = [&is_first,&db,this]() {
      if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo
      {
         db.remove( db.create<operation_history_object>( []( operation_history_object& obj) {} ) );
         is_first = false;
      }
      else
         _oho_index->use_next_id();
   };

   for( const optional< operation_history_object >& o_op : hist )
   {
      optional<operation_history_object> oho;

      auto create_oho = [&]() {
         is_first = false;
         return optional<operation_history_object>( db.create<operation_history_object>( [&]( operation_history_object& h )
         {
            if( o_op.valid() )
            {
               h.op           = o_op->op;
               h.result       = o_op->result;
               h.block_num    = o_op->block_num;
               h.trx_in_block = o_op->trx_in_block;
               h.op_in_trx    = o_op->op_in_trx;
               h.virtual_op   = o_op->virtual_op;
            }
         } ) );
      };

      if( !o_op.valid() || ( _max_ops_per_account == 0 && _partial_operations ) )
      {
         // Note: the 2nd and 3rd checks above are for better performance, when the db is not clean,
         //       they will break consistency of account_stats.total_ops and removed_ops and most_recent_op
         skip_oho_id();
         continue;
      }
      else if( !_partial_operations )
         // add to the operation history index
         oho = create_oho();

      const operation_history_object& op = *o_op;

      // get the set of accounts this operation applies to
      flat_set<account_id_type> impacted;
      vector<authority> other;
      operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here

      if( op.op.which() == operation::tag< account_create_operation >::value )
         impacted.insert( op.result.get<object_id_type>() );
      else
         graphene::chain::operation_get_impacted_accounts( op.op, impacted );

      for( auto& a : other )
         for( auto& item : a.account_auths )
            impacted.insert( item.first );

      // be here, either _max_ops_per_account > 0, or _partial_operations == false, or both
      // if _partial_operations == false, oho should have been created above
      // so the only case should be checked here is:
      //    whether need to create oho if _max_ops_per_account > 0 and _partial_operations == true

      // for each operation this account applies to that is in the config link it into the history
      if( _tracked_accounts.size() == 0 ) // tracking all accounts
      {
         // if tracking all accounts, when impacted is not empty (although it will always be),
         //    still need to create oho if _max_ops_per_account > 0 and _partial_operations == true
         //    so always need to create oho if not done
         if (!impacted.empty() && !oho.valid()) { oho = create_oho(); }

         if( _max_ops_per_account > 0 )
         {
            // Note: the check above is for better performance, when the db is not clean,
            //       it breaks consistency of account_stats.total_ops and removed_ops and most_recent_op,
            //       but it ensures it's safe to remove old entries in add_account_history(...)
            for( auto& account_id : impacted )
            {
               // we don't do index_account_keys here anymore, because
               // that indexing now happens in observers' post_evaluate()

               // add history
               add_account_history( account_id, oho->id );
            }
         }
      }
      else // tracking a subset of accounts
      {
         // whether need to create oho if _max_ops_per_account > 0 and _partial_operations == true ?
         // the answer: only need to create oho if a tracked account is impacted and need to save history

         if( _max_ops_per_account > 0 )
         {
            // Note: the check above is for better performance, when the db is not clean,
            //       it breaks consistency of account_stats.total_ops and removed_ops and most_recent_op,
            //       but it ensures it's safe to remove old entries in add_account_history(...)
            for( auto account_id : _tracked_accounts )
            {
               if( impacted.find( account_id ) != impacted.end() )
               {
                  if (!oho.valid()) { oho = create_oho(); }
                  // add history
                  add_account_history( account_id, oho->id );
               }
            }
         }
      }
      if (_partial_operations && ! oho.valid())
         skip_oho_id();
   }
}

void account_history_plugin_impl::add_account_history( const account_id_type account_id, const operation_history_id_type op_id )
{
   graphene::chain::database& db = database();
   const auto& stats_obj = account_id(db).statistics(db);
   // add new entry
   const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){
       obj.operation_id = op_id;
       obj.account = account_id;
       obj.sequence = stats_obj.total_ops + 1;
       obj.next = stats_obj.most_recent_op;
   });
   db.modify( stats_obj, [&]( account_statistics_object& obj ){
       obj.most_recent_op = ath.id;
       obj.total_ops = ath.sequence;
   });
   // remove the earliest account history entry if too many
   // _max_ops_per_account is guaranteed to be non-zero outside
   if( stats_obj.total_ops - stats_obj.removed_ops > _max_ops_per_account )
   {
      // look for the earliest entry
      const auto& his_idx = db.get_index_type<account_transaction_history_index>();
      const auto& by_seq_idx = his_idx.indices().get<by_seq>();
      auto itr = by_seq_idx.lower_bound( boost::make_tuple( account_id, 0 ) );
      // make sure don't remove the one just added
      if( itr != by_seq_idx.end() && itr->account == account_id && itr->id != ath.id )
      {
         // if found, remove the entry, and adjust account stats object
         const auto remove_op_id = itr->operation_id;
         const auto itr_remove = itr;
         ++itr;
         db.remove( *itr_remove );
         db.modify( stats_obj, [&]( account_statistics_object& obj ){
             obj.removed_ops = obj.removed_ops + 1;
         });
         // modify previous node's next pointer
         // this should be always true, but just have a check here
         if( itr != by_seq_idx.end() && itr->account == account_id )
         {
            db.modify( *itr, [&]( account_transaction_history_object& obj ){
               obj.next = account_transaction_history_id_type();
            });
         }
         // else need to modify the head pointer, but it shouldn't be true

         // remove the operation history entry (1.11.x) if configured and no reference left
         if( _partial_operations )
         {
            // check for references
            const auto& by_opid_idx = his_idx.indices().get<by_opid>();
            if( by_opid_idx.find( remove_op_id ) == by_opid_idx.end() )
            {
               // if no reference, remove
               db.remove( remove_op_id(db) );
            }
         }
      }
   }
}

} // end namespace detail

account_history_plugin::account_history_plugin() :
   my( new detail::account_history_plugin_impl(*this) )
{
}

account_history_plugin::~account_history_plugin()
{
}

std::string account_history_plugin::plugin_name()const
{
   return "account_history";
}

void account_history_plugin::plugin_set_program_options(
   boost::program_options::options_description& cli,
   boost::program_options::options_description& cfg
   )
{
   cli.add_options()
         ("track-account", boost::program_options::value<std::vector<std::string>>()->composing()->multitoken(), "Account ID to track history for (may specify multiple times)")
         ("partial-operations", boost::program_options::value<bool>(), "Keep only those operations in memory that are related to account history tracking")
         ("max-ops-per-account", boost::program_options::value<uint64_t>(), "Maximum number of operations per account will be kept in memory")
         ;
   cfg.add(cli);
}

void account_history_plugin::plugin_initialize(const boost::program_options::variables_map& options)
{
   database().applied_block.connect( [&]( const signed_block& b){ my->update_account_histories(b); } );
   my->_oho_index = database().add_index< primary_index< operation_history_index > >();
   database().add_index< primary_index< account_transaction_history_index > >();

   LOAD_VALUE_SET(options, "track-account", my->_tracked_accounts, graphene::chain::account_id_type);
   if (options.count("partial-operations")) {
       my->_partial_operations = options["partial-operations"].as<bool>();
   }
   if (options.count("max-ops-per-account")) {
       my->_max_ops_per_account = options["max-ops-per-account"].as<uint64_t>();
   }
}

void account_history_plugin::plugin_startup()
{
}

flat_set<account_id_type> account_history_plugin::tracked_accounts() const
{
   return my->_tracked_accounts;
}

} }
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unodoc.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-08-14 18:00:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
// System - Includes -----------------------------------------------------

#include <tools/string.hxx>
#include <sfx2/docfac.hxx>
#include "swdll.hxx"
#include "docsh.hxx"
#include "globdoc.hxx"
#include "wdocsh.hxx"

#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

using namespace ::com::sun::star;

//============================================================
// com.sun.star.comp.Writer.TextDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwTextDocument_getSupportedServiceNames() throw()
{
    // return only top level services here! All others must be
    // resolved by rtti!
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.TextDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwTextDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.TextDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwTextDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

//============================================================
// com.sun.star.comp.Writer.WebDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwWebDocument_getSupportedServiceNames() throw()
{
    // return only top level services here! All others must be
    // resolved by rtti!
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.WebDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwWebDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.WebDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwWebDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwWebDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

//============================================================
// com.sun.star.comp.Writer.GlobalDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwGlobalDocument_getSupportedServiceNames() throw()
{
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.GlobalDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwGlobalDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.GlobalDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwGlobalDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwGlobalDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.6.2); FILE MERGED 2006/09/01 17:53:30 kaib 1.6.2.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unodoc.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 23:30:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
// System - Includes -----------------------------------------------------

#include <tools/string.hxx>
#include <sfx2/docfac.hxx>
#include "swdll.hxx"
#include "docsh.hxx"
#include "globdoc.hxx"
#include "wdocsh.hxx"

#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

using namespace ::com::sun::star;

//============================================================
// com.sun.star.comp.Writer.TextDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwTextDocument_getSupportedServiceNames() throw()
{
    // return only top level services here! All others must be
    // resolved by rtti!
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.TextDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwTextDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.TextDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwTextDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

//============================================================
// com.sun.star.comp.Writer.WebDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwWebDocument_getSupportedServiceNames() throw()
{
    // return only top level services here! All others must be
    // resolved by rtti!
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.WebDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwWebDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.WebDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwWebDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwWebDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

//============================================================
// com.sun.star.comp.Writer.GlobalDocument

uno::Sequence< ::rtl::OUString > SAL_CALL SwGlobalDocument_getSupportedServiceNames() throw()
{
    uno::Sequence< ::rtl::OUString > aRet ( 1 );
    ::rtl::OUString* pArray = aRet.getArray();
    pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.text.GlobalDocument" ) );

    return aRet;
}

::rtl::OUString SAL_CALL SwGlobalDocument_getImplementationName() throw()
{
    return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Writer.GlobalDocument" ) );
}

uno::Reference< uno::XInterface > SAL_CALL SwGlobalDocument_createInstance( const uno::Reference< lang::XMultiServiceFactory > &rSMgr )
    throw( uno::Exception )
{
    ::vos::OGuard aGuard( Application::GetSolarMutex() );
    SwDLL::Init();
    SfxObjectShell* pShell = new SwGlobalDocShell( SFX_CREATE_MODE_STANDARD );
    return uno::Reference< uno::XInterface >( pShell->GetModel() );
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/common_types.h"

#include <string.h>

#include "webrtc/base/checks.h"

namespace webrtc {

int InStream::Rewind() {
  DCHECK(false);
  return -1;
}

int OutStream::Rewind() {
  DCHECK(false);
  return -1;
}

StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}

RTPHeader::RTPHeader()
    : markerBit(false),
      payloadType(0),
      sequenceNumber(0),
      timestamp(0),
      ssrc(0),
      numCSRCs(0),
      paddingLength(0),
      headerLength(0),
      payload_type_frequency(0),
      extension() {
  memset(&arrOfCSRCs, 0, sizeof(arrOfCSRCs));
}

}  // namespace webrtc
<commit_msg>Remove DCHECK from common_types.cc<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/common_types.h"

#include <string.h>

namespace webrtc {

int InStream::Rewind() { return -1; }

int OutStream::Rewind() { return -1; }

StreamDataCounters::StreamDataCounters() : first_packet_time_ms(-1) {}

RTPHeader::RTPHeader()
    : markerBit(false),
      payloadType(0),
      sequenceNumber(0),
      timestamp(0),
      ssrc(0),
      numCSRCs(0),
      paddingLength(0),
      headerLength(0),
      payload_type_frequency(0),
      extension() {
  memset(&arrOfCSRCs, 0, sizeof(arrOfCSRCs));
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <DTK_DetailsDistributedSearchTreeImpl.hpp>

#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_UnitTestHarness.hpp>
#include <Tpetra_Distributor.hpp>

#include <algorithm> // fill
#include <set>
#include <vector>

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( DetailsDistributedSearchTreeImpl, recv_from,
                                   DeviceType )
{
    // Checking that it is not necessary to send ranks because it can be
    // inferred from getProcsFrom() and getLengthsFrom().
    Teuchos::RCP<const Teuchos::Comm<int>> comm =
        Teuchos::DefaultComm<int>::getComm();
    int const comm_rank = comm->getRank();
    int const comm_size = comm->getSize();

    std::vector<int> tn( comm_size + 1 );
    for ( int i = 0; i < comm_size + 1; ++i )
        tn[i] = i * ( i - 1 ) / 2;

    // First use send buffer to set up the communication plan.  Sending 0
    // packet to rank 1, 1 packet to rank 1, 2 packets to rank 2, etc.
    int const n_exports = tn[comm_size];
    std::vector<int> exports( n_exports );
    for ( int i = 0; i < comm_size; ++i )
        for ( int j = tn[i]; j < tn[i + 1]; ++j )
            exports[j] = i;

    Tpetra::Distributor distributor( comm );
    int const n_imports = distributor.createFromSends(
        Teuchos::ArrayView<int>( exports.data(), exports.size() ) );
    TEST_EQUALITY( n_imports, comm_rank * comm_size );

    std::vector<int> imports( n_imports );
    distributor.doPostsAndWaits(
        Teuchos::ArrayView<int const>( exports.data(), exports.size() ), 1,
        Teuchos::ArrayView<int>( imports.data(), imports.size() ) );

    TEST_COMPARE_ARRAYS( imports, std::vector<int>( n_imports, comm_rank ) );

    // Then fill buffer with rank of the process that is sending packets.
    std::fill( exports.begin(), exports.end(), comm_rank );
    distributor.doPostsAndWaits(
        Teuchos::ArrayView<int const>( exports.data(), exports.size() ), 1,
        Teuchos::ArrayView<int>( imports.data(), imports.size() ) );

    auto procs_from = distributor.getProcsFrom();
    auto lengths_from = distributor.getLengthsFrom();
    TEST_EQUALITY( procs_from.size(), lengths_from.size() );
    std::vector<int> recv_from( n_imports, -1 );
    int count = 0;
    for ( auto i = 0; i < procs_from.size(); ++i )
        for ( size_t j = 0; j < lengths_from[i]; ++j )
            recv_from[count++] = procs_from[i];
    TEST_EQUALITY( count, n_imports );
    TEST_COMPARE_ARRAYS( imports, recv_from );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( DetailsDistributedSearchTreeImpl,
                                   sort_results, DeviceType )
{
    std::vector<int> ids_ = {4, 3, 2, 1, 4, 3, 2, 4, 3, 4};
    std::vector<int> sorted_ids = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
    std::vector<int> offset = {0, 1, 3, 6, 10};
    int const n = 10;
    int const m = 4;
    TEST_EQUALITY( ids_.size(), n );
    TEST_EQUALITY( sorted_ids.size(), n );
    TEST_EQUALITY( offset.size(), m + 1 );
    std::vector<int> results_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::vector<std::set<int>> sorted_results = {
        {3},
        {6, 2},
        {8, 5, 1},
        {9, 7, 4, 0},
    };
    std::vector<int> ranks_ = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
    std::vector<std::set<int>> sorted_ranks = {
        {13},
        {16, 12},
        {18, 15, 11},
        {19, 17, 14, 10},
    };
    TEST_EQUALITY( results_.size(), n );
    TEST_EQUALITY( ranks_.size(), n );

    Kokkos::View<int *, DeviceType> ids( "query_ids", n );
    auto ids_host = Kokkos::create_mirror_view( ids );
    for ( int i = 0; i < n; ++i )
        ids_host( i ) = ids_[i];
    Kokkos::deep_copy( ids, ids_host );

    Kokkos::View<int *, DeviceType> results( "results", n );
    auto results_host = Kokkos::create_mirror_view( results );
    for ( int i = 0; i < n; ++i )
        results_host( i ) = results_[i];
    Kokkos::deep_copy( results, results_host );

    Kokkos::View<int *, DeviceType> ranks( "ranks", n );
    auto ranks_host = Kokkos::create_mirror_view( ranks );
    for ( int i = 0; i < n; ++i )
        ranks_host( i ) = ranks_[i];
    Kokkos::deep_copy( ranks, ranks_host );

    DataTransferKit::Details::DistributedSearchTreeImpl<
        DeviceType>::sortResults( ids, results, ranks );

    // COMMENT: ids are untouched
    Kokkos::deep_copy( ids_host, ids );
    TEST_COMPARE_ARRAYS( ids_host, ids_ );

    Kokkos::deep_copy( results_host, results );
    Kokkos::deep_copy( ranks_host, ranks );
    for ( int q = 0; q < m; ++q )
        for ( int i = offset[q]; i < offset[q + 1]; ++i )
        {
            TEST_EQUALITY( sorted_results[q].count( results_host[i] ), 1 );
            TEST_EQUALITY( sorted_ranks[q].count( ranks_host[i] ), 1 );
        }

    Kokkos::View<int *, DeviceType> not_sized_properly( "", m );
    TEST_THROW( DataTransferKit::Details::DistributedSearchTreeImpl<
                    DeviceType>::sortResults( ids, not_sized_properly ),
                DataTransferKit::DataTransferKitException );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( DetailsDistributedSearchTreeImpl,
                                   count_results, DeviceType )
{
    std::vector<int> ids_ref = {4, 3, 2, 1, 4, 3, 2, 4, 3, 4};
    std::vector<int> offset_ref = {
        0, 0, 1, 3, 6, 10,
    };
    int const m = 5;
    int const nnz = 10;
    TEST_EQUALITY( ids_ref.size(), nnz );
    TEST_EQUALITY( offset_ref.size(), m + 1 );

    Kokkos::View<int *, DeviceType> ids( "query_ids", nnz );
    auto ids_host = Kokkos::create_mirror_view( ids );
    for ( int i = 0; i < nnz; ++i )
        ids_host( i ) = ids_ref[i];
    Kokkos::deep_copy( ids, ids_host );

    Kokkos::View<int *, DeviceType> offset( "offset" );

    DataTransferKit::Details::DistributedSearchTreeImpl<
        DeviceType>::countResults( m, ids, offset );

    auto offset_host = Kokkos::create_mirror_view( offset );
    Kokkos::deep_copy( offset_host, offset );
    TEST_COMPARE_ARRAYS( offset_host, offset_ref );
}

template <typename View1, typename View2>
inline void checkViewWasNotAllocated( View1 const &v1, View2 const &v2,
                                      bool &success,
                                      Teuchos::FancyOStream &out )
{
    // NOTE: cannot use operator== here because array layout may "change" for
    // rank-1 views
    TEST_EQUALITY( v1.data(), v2.data() );
    TEST_EQUALITY( v1.span(), v2.span() );

    TEST_EQUALITY( (int)View1::rank, (int)View2::rank );
    TEST_ASSERT( ( std::is_same<typename View1::const_value_type,
                                typename View2::const_value_type>::value ) );
    TEST_ASSERT( ( std::is_same<typename View1::memory_space,
                                typename View2::memory_space>::value ) );

    TEST_EQUALITY( v1.dimension_0(), v2.dimension_0() );
    TEST_EQUALITY( v1.dimension_1(), v2.dimension_1() );
    TEST_EQUALITY( v1.dimension_2(), v2.dimension_2() );
    TEST_EQUALITY( v1.dimension_3(), v2.dimension_3() );
    TEST_EQUALITY( v1.dimension_4(), v2.dimension_4() );
    TEST_EQUALITY( v1.dimension_5(), v2.dimension_5() );
    TEST_EQUALITY( v1.dimension_6(), v2.dimension_6() );
    TEST_EQUALITY( v1.dimension_7(), v2.dimension_7() );
}

template <typename View1, typename View2>
inline void checkNewViewWasAllocated( View1 const &v1, View2 const &v2,
                                      bool &success,
                                      Teuchos::FancyOStream &out )
{
    TEST_INEQUALITY( v1.data(), v2.data() );

    TEST_EQUALITY( (int)View1::rank, (int)View2::rank );
    TEST_ASSERT( ( std::is_same<typename View1::const_value_type,
                                typename View2::const_value_type>::value ) );

    TEST_EQUALITY( v1.dimension_0(), v2.dimension_0() );
    TEST_EQUALITY( v1.dimension_1(), v2.dimension_1() );
    TEST_EQUALITY( v1.dimension_2(), v2.dimension_2() );
    TEST_EQUALITY( v1.dimension_3(), v2.dimension_3() );
    TEST_EQUALITY( v1.dimension_4(), v2.dimension_4() );
    TEST_EQUALITY( v1.dimension_5(), v2.dimension_5() );
    TEST_EQUALITY( v1.dimension_6(), v2.dimension_6() );
    TEST_EQUALITY( v1.dimension_7(), v2.dimension_7() );
}

TEUCHOS_UNIT_TEST( DetailsDistributedSearchTreeImpl,
                   create_layout_right_mirror_view )
{
    using DataTransferKit::Details::create_layout_right_mirror_view;
    using Kokkos::ALL;
    using Kokkos::LayoutLeft;
    using Kokkos::LayoutRight;
    using Kokkos::make_pair;
    using Kokkos::subview;
    using Kokkos::View;

    // rank-1 and not strided -> do not allocate
    View<int *, LayoutLeft> u( "u", 255 );
    auto u_h = create_layout_right_mirror_view( u );
    checkViewWasNotAllocated( u, u_h, success, out );

    // right layout -> do not allocate
    View<int **, LayoutRight> v( "v", 2, 3 );
    auto v_h = create_layout_right_mirror_view( v );
    checkViewWasNotAllocated( v, v_h, success, out );

    // left layout and rank > 1 -> allocate
    View<int **, LayoutLeft> w( "w", 4, 5 );
    auto w_h = create_layout_right_mirror_view( w );
    checkNewViewWasAllocated( w, w_h, success, out );

    // strided layout -> allocate
    auto x = subview( v, ALL, 0 );
    auto x_h = create_layout_right_mirror_view( x );
    checkNewViewWasAllocated( x, x_h, success, out );

    // subview is rank-1 and not strided -> do not allocate
    auto y = subview( u, make_pair( 8, 16 ) );
    auto y_h = create_layout_right_mirror_view( y );
    checkViewWasNotAllocated( y, y_h, success, out );
}

// Include the test macros.
#include "DataTransferKit_ETIHelperMacros.h"

// Create the test group
#define UNIT_TEST_GROUP( NODE )                                                \
    using DeviceType##NODE = typename NODE::device_type;                       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( DetailsDistributedSearchTreeImpl,    \
                                          recv_from, DeviceType##NODE )        \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( DetailsDistributedSearchTreeImpl,    \
                                          sort_results, DeviceType##NODE )     \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( DetailsDistributedSearchTreeImpl,    \
                                          count_results, DeviceType##NODE )

// Demangle the types
DTK_ETI_MANGLING_TYPEDEFS()

// Instantiate the tests
DTK_INSTANTIATE_N( UNIT_TEST_GROUP )
<commit_msg>Remove test checking that it is not necessary to pass ranks with a Tpetra::Distributor<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <DTK_DetailsDistributedSearchTreeImpl.hpp>

#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_UnitTestHarness.hpp>

#include <algorithm> // fill
#include <set>
#include <vector>

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( DetailsDistributedSearchTreeImpl,
                                   sort_results, DeviceType )
{
    std::vector<int> ids_ = {4, 3, 2, 1, 4, 3, 2, 4, 3, 4};
    std::vector<int> sorted_ids = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
    std::vector<int> offset = {0, 1, 3, 6, 10};
    int const n = 10;
    int const m = 4;
    TEST_EQUALITY( ids_.size(), n );
    TEST_EQUALITY( sorted_ids.size(), n );
    TEST_EQUALITY( offset.size(), m + 1 );
    std::vector<int> results_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::vector<std::set<int>> sorted_results = {
        {3},
        {6, 2},
        {8, 5, 1},
        {9, 7, 4, 0},
    };
    std::vector<int> ranks_ = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
    std::vector<std::set<int>> sorted_ranks = {
        {13},
        {16, 12},
        {18, 15, 11},
        {19, 17, 14, 10},
    };
    TEST_EQUALITY( results_.size(), n );
    TEST_EQUALITY( ranks_.size(), n );

    Kokkos::View<int *, DeviceType> ids( "query_ids", n );
    auto ids_host = Kokkos::create_mirror_view( ids );
    for ( int i = 0; i < n; ++i )
        ids_host( i ) = ids_[i];
    Kokkos::deep_copy( ids, ids_host );

    Kokkos::View<int *, DeviceType> results( "results", n );
    auto results_host = Kokkos::create_mirror_view( results );
    for ( int i = 0; i < n; ++i )
        results_host( i ) = results_[i];
    Kokkos::deep_copy( results, results_host );

    Kokkos::View<int *, DeviceType> ranks( "ranks", n );
    auto ranks_host = Kokkos::create_mirror_view( ranks );
    for ( int i = 0; i < n; ++i )
        ranks_host( i ) = ranks_[i];
    Kokkos::deep_copy( ranks, ranks_host );

    DataTransferKit::Details::DistributedSearchTreeImpl<
        DeviceType>::sortResults( ids, results, ranks );

    // COMMENT: ids are untouched
    Kokkos::deep_copy( ids_host, ids );
    TEST_COMPARE_ARRAYS( ids_host, ids_ );

    Kokkos::deep_copy( results_host, results );
    Kokkos::deep_copy( ranks_host, ranks );
    for ( int q = 0; q < m; ++q )
        for ( int i = offset[q]; i < offset[q + 1]; ++i )
        {
            TEST_EQUALITY( sorted_results[q].count( results_host[i] ), 1 );
            TEST_EQUALITY( sorted_ranks[q].count( ranks_host[i] ), 1 );
        }

    Kokkos::View<int *, DeviceType> not_sized_properly( "", m );
    TEST_THROW( DataTransferKit::Details::DistributedSearchTreeImpl<
                    DeviceType>::sortResults( ids, not_sized_properly ),
                DataTransferKit::DataTransferKitException );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( DetailsDistributedSearchTreeImpl,
                                   count_results, DeviceType )
{
    std::vector<int> ids_ref = {4, 3, 2, 1, 4, 3, 2, 4, 3, 4};
    std::vector<int> offset_ref = {
        0, 0, 1, 3, 6, 10,
    };
    int const m = 5;
    int const nnz = 10;
    TEST_EQUALITY( ids_ref.size(), nnz );
    TEST_EQUALITY( offset_ref.size(), m + 1 );

    Kokkos::View<int *, DeviceType> ids( "query_ids", nnz );
    auto ids_host = Kokkos::create_mirror_view( ids );
    for ( int i = 0; i < nnz; ++i )
        ids_host( i ) = ids_ref[i];
    Kokkos::deep_copy( ids, ids_host );

    Kokkos::View<int *, DeviceType> offset( "offset" );

    DataTransferKit::Details::DistributedSearchTreeImpl<
        DeviceType>::countResults( m, ids, offset );

    auto offset_host = Kokkos::create_mirror_view( offset );
    Kokkos::deep_copy( offset_host, offset );
    TEST_COMPARE_ARRAYS( offset_host, offset_ref );
}

template <typename View1, typename View2>
inline void checkViewWasNotAllocated( View1 const &v1, View2 const &v2,
                                      bool &success,
                                      Teuchos::FancyOStream &out )
{
    // NOTE: cannot use operator== here because array layout may "change" for
    // rank-1 views
    TEST_EQUALITY( v1.data(), v2.data() );
    TEST_EQUALITY( v1.span(), v2.span() );

    TEST_EQUALITY( (int)View1::rank, (int)View2::rank );
    TEST_ASSERT( ( std::is_same<typename View1::const_value_type,
                                typename View2::const_value_type>::value ) );
    TEST_ASSERT( ( std::is_same<typename View1::memory_space,
                                typename View2::memory_space>::value ) );

    TEST_EQUALITY( v1.dimension_0(), v2.dimension_0() );
    TEST_EQUALITY( v1.dimension_1(), v2.dimension_1() );
    TEST_EQUALITY( v1.dimension_2(), v2.dimension_2() );
    TEST_EQUALITY( v1.dimension_3(), v2.dimension_3() );
    TEST_EQUALITY( v1.dimension_4(), v2.dimension_4() );
    TEST_EQUALITY( v1.dimension_5(), v2.dimension_5() );
    TEST_EQUALITY( v1.dimension_6(), v2.dimension_6() );
    TEST_EQUALITY( v1.dimension_7(), v2.dimension_7() );
}

template <typename View1, typename View2>
inline void checkNewViewWasAllocated( View1 const &v1, View2 const &v2,
                                      bool &success,
                                      Teuchos::FancyOStream &out )
{
    TEST_INEQUALITY( v1.data(), v2.data() );

    TEST_EQUALITY( (int)View1::rank, (int)View2::rank );
    TEST_ASSERT( ( std::is_same<typename View1::const_value_type,
                                typename View2::const_value_type>::value ) );

    TEST_EQUALITY( v1.dimension_0(), v2.dimension_0() );
    TEST_EQUALITY( v1.dimension_1(), v2.dimension_1() );
    TEST_EQUALITY( v1.dimension_2(), v2.dimension_2() );
    TEST_EQUALITY( v1.dimension_3(), v2.dimension_3() );
    TEST_EQUALITY( v1.dimension_4(), v2.dimension_4() );
    TEST_EQUALITY( v1.dimension_5(), v2.dimension_5() );
    TEST_EQUALITY( v1.dimension_6(), v2.dimension_6() );
    TEST_EQUALITY( v1.dimension_7(), v2.dimension_7() );
}

TEUCHOS_UNIT_TEST( DetailsDistributedSearchTreeImpl,
                   create_layout_right_mirror_view )
{
    using DataTransferKit::Details::create_layout_right_mirror_view;
    using Kokkos::ALL;
    using Kokkos::LayoutLeft;
    using Kokkos::LayoutRight;
    using Kokkos::make_pair;
    using Kokkos::subview;
    using Kokkos::View;

    // rank-1 and not strided -> do not allocate
    View<int *, LayoutLeft> u( "u", 255 );
    auto u_h = create_layout_right_mirror_view( u );
    checkViewWasNotAllocated( u, u_h, success, out );

    // right layout -> do not allocate
    View<int **, LayoutRight> v( "v", 2, 3 );
    auto v_h = create_layout_right_mirror_view( v );
    checkViewWasNotAllocated( v, v_h, success, out );

    // left layout and rank > 1 -> allocate
    View<int **, LayoutLeft> w( "w", 4, 5 );
    auto w_h = create_layout_right_mirror_view( w );
    checkNewViewWasAllocated( w, w_h, success, out );

    // strided layout -> allocate
    auto x = subview( v, ALL, 0 );
    auto x_h = create_layout_right_mirror_view( x );
    checkNewViewWasAllocated( x, x_h, success, out );

    // subview is rank-1 and not strided -> do not allocate
    auto y = subview( u, make_pair( 8, 16 ) );
    auto y_h = create_layout_right_mirror_view( y );
    checkViewWasNotAllocated( y, y_h, success, out );
}

// Include the test macros.
#include "DataTransferKit_ETIHelperMacros.h"

// Create the test group
#define UNIT_TEST_GROUP( NODE )                                                \
    using DeviceType##NODE = typename NODE::device_type;                       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( DetailsDistributedSearchTreeImpl,    \
                                          sort_results, DeviceType##NODE )     \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( DetailsDistributedSearchTreeImpl,    \
                                          count_results, DeviceType##NODE )

// Demangle the types
DTK_ETI_MANGLING_TYPEDEFS()

// Instantiate the tests
DTK_INSTANTIATE_N( UNIT_TEST_GROUP )
<|endoftext|>