v8_context_tracker_browsertest.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/performance_manager/v8_memory/v8_context_tracker.h"
  5. #include <memory>
  6. #include "base/strings/stringprintf.h"
  7. #include "components/performance_manager/execution_context/execution_context_registry_impl.h"
  8. #include "components/performance_manager/public/graph/graph.h"
  9. #include "components/performance_manager/test_support/performance_manager_browsertest_harness.h"
  10. #include "content/public/browser/render_frame_host.h"
  11. #include "content/public/test/browser_test.h"
  12. #include "content/public/test/browser_test_utils.h"
  13. #include "content/public/test/content_browser_test_utils.h"
  14. #include "content/shell/browser/shell.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #include "url/gurl.h"
  18. namespace performance_manager {
  19. namespace v8_memory {
  20. class V8ContextTrackerTest : public PerformanceManagerBrowserTestHarness {
  21. public:
  22. using Super = PerformanceManagerBrowserTestHarness;
  23. V8ContextTrackerTest() = default;
  24. ~V8ContextTrackerTest() override = default;
  25. void SetUp() override {
  26. GetGraphFeatures().EnableV8ContextTracker();
  27. Super::SetUp();
  28. }
  29. void ExpectCounts(size_t v8_context_count,
  30. size_t execution_context_count,
  31. size_t detached_v8_context_count,
  32. size_t destroyed_execution_context_count) {
  33. RunInGraph([&](Graph* graph) {
  34. auto* v8ct = V8ContextTracker::GetFromGraph(graph);
  35. ASSERT_TRUE(v8ct);
  36. EXPECT_EQ(v8_context_count, v8ct->GetV8ContextCountForTesting());
  37. EXPECT_EQ(execution_context_count,
  38. v8ct->GetExecutionContextCountForTesting());
  39. EXPECT_EQ(detached_v8_context_count,
  40. v8ct->GetDetachedV8ContextCountForTesting());
  41. EXPECT_EQ(destroyed_execution_context_count,
  42. v8ct->GetDestroyedExecutionContextCountForTesting());
  43. });
  44. }
  45. };
  46. IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, AboutBlank) {
  47. ExpectCounts(0, 0, 0, 0);
  48. ASSERT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
  49. ExpectCounts(1, 1, 0, 0);
  50. }
  51. IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameOriginIframeAttributionData) {
  52. GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_a.html"));
  53. auto* contents = shell()->web_contents();
  54. ASSERT_TRUE(
  55. NavigateAndWaitForConsoleMessage(contents, urla, "a.html loaded"));
  56. // Get pointers to the RFHs for each frame.
  57. content::RenderFrameHost* main_rfh = contents->GetPrimaryMainFrame();
  58. content::RenderFrameHost* child_rfh = ChildFrameAt(main_rfh, 0);
  59. ASSERT_TRUE(child_rfh);
  60. auto frame_node =
  61. PerformanceManager::GetFrameNodeForRenderFrameHost(child_rfh);
  62. RunInGraph([&frame_node](Graph* graph) {
  63. ASSERT_TRUE(frame_node);
  64. auto* v8_context_tracker = V8ContextTracker::GetFromGraph(graph);
  65. ASSERT_TRUE(v8_context_tracker);
  66. auto* ec_state = v8_context_tracker->GetExecutionContextState(
  67. frame_node->GetFrameToken());
  68. ASSERT_TRUE(ec_state);
  69. ASSERT_TRUE(ec_state->iframe_attribution_data);
  70. });
  71. }
  72. IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, CrossOriginIframeAttributionData) {
  73. GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
  74. auto* contents = shell()->web_contents();
  75. ASSERT_TRUE(
  76. NavigateAndWaitForConsoleMessage(contents, urla, "b.html loaded"));
  77. // Get pointers to the RFHs for each frame.
  78. content::RenderFrameHost* main_rfh = contents->GetPrimaryMainFrame();
  79. content::RenderFrameHost* child_rfh = ChildFrameAt(main_rfh, 0);
  80. ASSERT_TRUE(child_rfh);
  81. auto frame_node =
  82. PerformanceManager::GetFrameNodeForRenderFrameHost(child_rfh);
  83. RunInGraph([&frame_node](Graph* graph) {
  84. ASSERT_TRUE(frame_node);
  85. auto* v8_context_tracker = V8ContextTracker::GetFromGraph(graph);
  86. ASSERT_TRUE(v8_context_tracker);
  87. auto* ec_state = v8_context_tracker->GetExecutionContextState(
  88. frame_node->GetFrameToken());
  89. ASSERT_TRUE(ec_state);
  90. ASSERT_TRUE(ec_state->iframe_attribution_data)
  91. << "url " << frame_node->GetURL() << ", current "
  92. << frame_node->IsCurrent() << ", state "
  93. << frame_node->GetLifecycleState();
  94. });
  95. }
  96. IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameDocNavigation) {
  97. ExpectCounts(0, 0, 0, 0);
  98. auto* contents = shell()->web_contents();
  99. GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
  100. ASSERT_TRUE(
  101. NavigateAndWaitForConsoleMessage(contents, urla, "b.html loaded"));
  102. ExpectCounts(2, 2, 0, 0);
  103. // Get pointers to the RFHs for each frame.
  104. content::RenderFrameHost* rfha = contents->GetPrimaryMainFrame();
  105. content::RenderFrameHost* rfhb = ChildFrameAt(rfha, 0);
  106. // Execute a same document navigation in the child frame. This causes a
  107. // v8 context to be detached, and new context attached to the execution
  108. // context. So there will remain 2 execution contexts, there will be 3
  109. // v8 contexts, 1 one of which is detached.
  110. GURL urlb(embedded_test_server()->GetURL("b.com", "/b.html?foo=bar"));
  111. ASSERT_TRUE(ExecJs(
  112. rfhb, base::StringPrintf("location.href = \"%s\"", urlb.spec().c_str())));
  113. WaitForLoad(contents);
  114. ExpectCounts(3, 2, 1, 0);
  115. }
  116. IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, DetachedContext) {
  117. ExpectCounts(0, 0, 0, 0);
  118. auto* contents = shell()->web_contents();
  119. GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_a.html"));
  120. ASSERT_TRUE(
  121. NavigateAndWaitForConsoleMessage(contents, urla, "a.html loaded"));
  122. ExpectCounts(2, 2, 0, 0);
  123. // Get pointers to the RFHs for each frame.
  124. content::RenderFrameHost* rfha = contents->GetPrimaryMainFrame();
  125. // Keep a pointer to the window associated with the child iframe, but
  126. // unload it.
  127. ASSERT_TRUE(ExecJs(rfha,
  128. "let iframe = document.getElementsByTagName('iframe')[0]; "
  129. "document.body.leakyRef = iframe.contentWindow.window; "
  130. "iframe.parentNode.removeChild(iframe); "
  131. "console.log('detached and leaked iframe');"));
  132. ExpectCounts(2, 2, 1, 1);
  133. }
  134. } // namespace v8_memory
  135. } // namespace performance_manager