web_memory_impl_unittest.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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/web_memory_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/containers/flat_map.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/run_loop.h"
  11. #include "base/test/bind.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/time/time.h"
  14. #include "components/performance_manager/graph/frame_node_impl.h"
  15. #include "components/performance_manager/public/graph/frame_node.h"
  16. #include "components/performance_manager/public/mojom/web_memory.mojom.h"
  17. #include "components/performance_manager/public/performance_manager.h"
  18. #include "components/performance_manager/public/v8_memory/v8_detailed_memory.h"
  19. #include "components/performance_manager/public/v8_memory/web_memory.h"
  20. #include "components/performance_manager/v8_memory/v8_memory_test_helpers.h"
  21. #include "content/public/browser/render_frame_host.h"
  22. #include "content/public/test/test_renderer_host.h"
  23. #include "testing/gmock/include/gmock/gmock.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. #include "third_party/blink/public/common/tokens/tokens.h"
  26. namespace performance_manager {
  27. namespace v8_memory {
  28. using WebMemoryImplPMTest = V8MemoryPerformanceManagerTestHarness;
  29. class WebMemoryImplTest : public WebMemoryTestHarness {
  30. protected:
  31. void MeasureAndVerify(FrameNodeImpl* frame,
  32. base::flat_map<std::string, Bytes> expected);
  33. };
  34. class FakeSecurityChecker : public WebMeasureMemorySecurityChecker {
  35. public:
  36. explicit FakeSecurityChecker(bool allowed) : allowed_(allowed) {}
  37. void CheckMeasureMemoryIsAllowed(
  38. const FrameNode* frame_node,
  39. MeasureMemoryCallback measure_memory_callback,
  40. mojo::ReportBadMessageCallback bad_message_callback) const override {
  41. if (allowed_) {
  42. std::move(measure_memory_callback)
  43. .Run(FrameNodeImpl::FromNode(frame_node)->GetWeakPtr());
  44. } else {
  45. std::move(bad_message_callback).Run("disallowed");
  46. }
  47. }
  48. private:
  49. bool allowed_;
  50. };
  51. void WebMemoryImplTest::MeasureAndVerify(
  52. FrameNodeImpl* frame,
  53. base::flat_map<std::string, Bytes> expected) {
  54. bool measurement_done = false;
  55. WebMemoryMeasurer web_memory(
  56. frame->frame_token(), V8DetailedMemoryRequest::MeasurementMode::kDefault,
  57. base::BindLambdaForTesting([&measurement_done, &expected](
  58. mojom::WebMemoryMeasurementPtr result) {
  59. base::flat_map<std::string, Bytes> actual;
  60. for (const auto& entry : result->breakdown) {
  61. EXPECT_EQ(1u, entry->attribution.size());
  62. std::string attribution_tag =
  63. (mojom::WebMemoryAttribution::Scope::kWindow ==
  64. entry->attribution[0]->scope)
  65. ? *entry->attribution[0]->url
  66. : *entry->attribution[0]->src;
  67. actual[attribution_tag] =
  68. entry->memory ? Bytes{entry->memory->bytes} : absl::nullopt;
  69. }
  70. EXPECT_EQ(expected, actual);
  71. measurement_done = true;
  72. }));
  73. V8DetailedMemoryProcessData process_data;
  74. web_memory.MeasurementComplete(process_node(), &process_data);
  75. EXPECT_TRUE(measurement_done);
  76. }
  77. TEST_F(WebMemoryImplTest, MeasurerIncludesSameOriginRelatedFrames) {
  78. auto* main = AddFrameNode("http://foo.com/", Bytes{10u});
  79. AddFrameNode("http://foo.com/iframe", Bytes{20}, main);
  80. MeasureAndVerify(main, {
  81. {"http://foo.com/", Bytes{10u}},
  82. {"http://foo.com/iframe", Bytes{20u}},
  83. });
  84. }
  85. TEST_F(WebMemoryImplTest, MeasurerIncludesCrossOriginFrames) {
  86. auto* main = AddFrameNode("http://foo.com", Bytes{10u});
  87. AddFrameNode("http://bar.com/iframe", Bytes{20}, main, "bar_id",
  88. "http://bar.com/iframe_src");
  89. MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}},
  90. {
  91. "http://bar.com/iframe_src",
  92. Bytes{20},
  93. }});
  94. }
  95. TEST_F(WebMemoryImplTest, MeasurerSkipsCrossBrowserContextGroupFrames) {
  96. auto* main = AddFrameNode("http://foo.com", Bytes{10u});
  97. AddCrossBrowsingInstanceFrameNode("http://foo.com/unrelated", Bytes{20});
  98. MeasureAndVerify(main, {{"http://foo.com/", Bytes{10u}}});
  99. }
  100. TEST_F(WebMemoryImplPMTest, WebMeasureMemory) {
  101. blink::LocalFrameToken frame_token =
  102. blink::LocalFrameToken(main_frame()->GetFrameToken());
  103. // Call WebMeasureMemory on the performance manager sequence and verify that
  104. // the result matches the data provided by the mock reporter.
  105. base::RunLoop run_loop;
  106. auto measurement_callback =
  107. base::BindLambdaForTesting([&](mojom::WebMemoryMeasurementPtr result) {
  108. EXPECT_EQ(1u, result->breakdown.size());
  109. const auto& entry = result->breakdown[0];
  110. EXPECT_EQ(1u, entry->attribution.size());
  111. EXPECT_EQ(kMainFrameUrl, *(entry->attribution[0]->url));
  112. ASSERT_TRUE(entry->memory);
  113. EXPECT_EQ(1001u, entry->memory->bytes);
  114. run_loop.Quit();
  115. });
  116. auto bad_message_callback =
  117. base::BindLambdaForTesting([&](base::StringPiece error) {
  118. ADD_FAILURE() << error;
  119. run_loop.Quit();
  120. });
  121. base::WeakPtr<FrameNode> frame_node_wrapper =
  122. PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
  123. PerformanceManager::CallOnGraph(
  124. FROM_HERE, base::BindLambdaForTesting([&]() {
  125. ASSERT_TRUE(frame_node_wrapper);
  126. FrameNode* frame_node = frame_node_wrapper.get();
  127. WebMeasureMemory(
  128. frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
  129. std::make_unique<FakeSecurityChecker>(true),
  130. std::move(measurement_callback), std::move(bad_message_callback));
  131. }));
  132. // Set up and bind the mock reporter.
  133. MockV8DetailedMemoryReporter mock_reporter;
  134. {
  135. auto data = NewPerProcessV8MemoryUsage(1);
  136. AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
  137. ExpectBindAndRespondToQuery(&mock_reporter, std::move(data),
  138. main_process_id());
  139. }
  140. // Finally, run all tasks to verify that the memory measurement callback
  141. // is actually invoked. The test will time out if not.
  142. run_loop.Run();
  143. }
  144. TEST_F(WebMemoryImplPMTest, MeasurementInterrupted) {
  145. CreateCrossProcessChildFrame();
  146. blink::LocalFrameToken frame_token =
  147. blink::LocalFrameToken(child_frame()->GetFrameToken());
  148. // Call WebMeasureMemory on the performance manager sequence but delete the
  149. // process being measured before the result arrives.
  150. auto measurement_callback =
  151. base::BindOnce([](mojom::WebMemoryMeasurementPtr result) {
  152. FAIL() << "Measurement callback ran unexpectedly";
  153. });
  154. auto bad_message_callback =
  155. base::BindOnce([](base::StringPiece error) { FAIL() << error; });
  156. base::WeakPtr<FrameNode> frame_node_wrapper =
  157. PerformanceManager::GetFrameNodeForRenderFrameHost(child_frame());
  158. PerformanceManager::CallOnGraph(
  159. FROM_HERE, base::BindLambdaForTesting([&]() {
  160. ASSERT_TRUE(frame_node_wrapper);
  161. FrameNode* frame_node = frame_node_wrapper.get();
  162. WebMeasureMemory(
  163. frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
  164. std::make_unique<FakeSecurityChecker>(true),
  165. std::move(measurement_callback), std::move(bad_message_callback));
  166. }));
  167. // Set up and bind the mock reporter.
  168. MockV8DetailedMemoryReporter mock_reporter;
  169. {
  170. ::testing::InSequence seq;
  171. ExpectBindReceiver(&mock_reporter, child_process_id());
  172. auto data = NewPerProcessV8MemoryUsage(1);
  173. AddIsolateMemoryUsage(frame_token, 1001u, data->isolates[0].get());
  174. ExpectQueryAndDelayReply(&mock_reporter, base::Seconds(10),
  175. std::move(data));
  176. }
  177. // Verify that requests are sent but reply is not yet received.
  178. task_environment()->FastForwardBy(base::Seconds(5));
  179. ::testing::Mock::VerifyAndClearExpectations(&mock_reporter);
  180. // Remove the child frame, which will destroy the child process.
  181. content::RenderFrameHostTester::For(child_frame())->Detach();
  182. // Advance until the reply is expected to make sure nothing explodes.
  183. task_environment()->FastForwardBy(base::Seconds(5));
  184. }
  185. TEST_F(WebMemoryImplPMTest, MeasurementDisallowed) {
  186. // Call WebMeasureMemory on the performance manager sequence but expect the
  187. // mojo ReportBadMessage callback to be called.
  188. base::RunLoop run_loop;
  189. auto measurement_callback =
  190. base::BindLambdaForTesting([&](mojom::WebMemoryMeasurementPtr result) {
  191. ADD_FAILURE() << "Measurement callback ran unexpectedly.";
  192. run_loop.Quit();
  193. });
  194. auto bad_message_callback =
  195. base::BindLambdaForTesting([&](base::StringPiece error) {
  196. SUCCEED() << error;
  197. run_loop.Quit();
  198. });
  199. base::WeakPtr<FrameNode> frame_node_wrapper =
  200. PerformanceManager::GetFrameNodeForRenderFrameHost(main_frame());
  201. PerformanceManager::CallOnGraph(
  202. FROM_HERE, base::BindLambdaForTesting([&]() {
  203. ASSERT_TRUE(frame_node_wrapper);
  204. FrameNode* frame_node = frame_node_wrapper.get();
  205. WebMeasureMemory(
  206. frame_node, mojom::WebMemoryMeasurement::Mode::kDefault,
  207. std::make_unique<FakeSecurityChecker>(false),
  208. std::move(measurement_callback), std::move(bad_message_callback));
  209. }));
  210. run_loop.Run();
  211. }
  212. } // namespace v8_memory
  213. } // namespace performance_manager