v8_context_tracker_helpers_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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_helpers.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "components/performance_manager/execution_context/execution_context_registry_impl.h"
  7. #include "components/performance_manager/graph/frame_node_impl.h"
  8. #include "components/performance_manager/graph/worker_node_impl.h"
  9. #include "components/performance_manager/public/execution_context/execution_context.h"
  10. #include "components/performance_manager/public/mojom/v8_contexts.mojom.h"
  11. #include "components/performance_manager/test_support/graph_test_harness.h"
  12. #include "components/performance_manager/test_support/mock_graphs.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace performance_manager {
  15. namespace v8_memory {
  16. namespace {
  17. constexpr char kValidExtensionWorldName[] = "abcdefghijklmnopabcdefghijklmnop";
  18. constexpr char kInvalidExtensionWorldName[] = "BADEXTENSIONNAME";
  19. constexpr char kWorldName[] = "worldname";
  20. class V8ContextTrackerHelpersTest : public GraphTestHarness {
  21. public:
  22. V8ContextTrackerHelpersTest() = default;
  23. ~V8ContextTrackerHelpersTest() override = default;
  24. void OnGraphCreated(GraphImpl* graph_impl) override {
  25. registry = graph_impl->PassToGraph(
  26. std::make_unique<execution_context::ExecutionContextRegistryImpl>());
  27. mock_graph =
  28. std::make_unique<MockSinglePageWithMultipleProcessesGraph>(graph());
  29. }
  30. raw_ptr<execution_context::ExecutionContextRegistry> registry = nullptr;
  31. std::unique_ptr<MockSinglePageWithMultipleProcessesGraph> mock_graph;
  32. mojom::IframeAttributionData fake_iframe_attribution_data;
  33. };
  34. } // namespace
  35. TEST_F(V8ContextTrackerHelpersTest, ToExecutionContextToken) {
  36. blink::DedicatedWorkerToken dedicated;
  37. blink::ServiceWorkerToken service;
  38. blink::SharedWorkerToken shared;
  39. EXPECT_EQ(blink::ExecutionContextToken(dedicated),
  40. ToExecutionContextToken(blink::WorkerToken(dedicated)));
  41. EXPECT_EQ(blink::ExecutionContextToken(service),
  42. ToExecutionContextToken(blink::WorkerToken(service)));
  43. EXPECT_EQ(blink::ExecutionContextToken(shared),
  44. ToExecutionContextToken(blink::WorkerToken(shared)));
  45. }
  46. TEST_F(V8ContextTrackerHelpersTest, HasCrossProcessParent) {
  47. // Fails for a main-frame.
  48. EXPECT_FALSE(HasCrossProcessParent(mock_graph->frame.get()));
  49. // Returns true for an actual cross-process child frame.
  50. EXPECT_TRUE(HasCrossProcessParent(mock_graph->child_frame.get()));
  51. // Fails for a same-process child frame.
  52. TestNodeWrapper<FrameNodeImpl> child_frame(graph()->CreateFrameNodeAutoId(
  53. mock_graph->process.get(), mock_graph->page.get(),
  54. mock_graph->frame.get()));
  55. EXPECT_FALSE(HasCrossProcessParent(child_frame.get()));
  56. }
  57. TEST_F(V8ContextTrackerHelpersTest, IsValidExtensionId) {
  58. EXPECT_TRUE(IsValidExtensionId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
  59. EXPECT_FALSE(IsValidExtensionId("Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
  60. EXPECT_FALSE(IsValidExtensionId("qaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
  61. EXPECT_FALSE(IsValidExtensionId("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
  62. EXPECT_FALSE(IsValidExtensionId(""));
  63. }
  64. TEST_F(V8ContextTrackerHelpersTest, IsWorkletToken) {
  65. blink::LocalFrameToken local_frame;
  66. blink::DedicatedWorkerToken dedicated;
  67. blink::ServiceWorkerToken service;
  68. blink::SharedWorkerToken shared;
  69. blink::AnimationWorkletToken animation;
  70. blink::AudioWorkletToken audio;
  71. blink::LayoutWorkletToken layout;
  72. blink::PaintWorkletToken paint;
  73. EXPECT_FALSE(IsWorkletToken(blink::ExecutionContextToken(local_frame)));
  74. EXPECT_FALSE(IsWorkletToken(blink::ExecutionContextToken(dedicated)));
  75. EXPECT_FALSE(IsWorkletToken(blink::ExecutionContextToken(service)));
  76. EXPECT_FALSE(IsWorkletToken(blink::ExecutionContextToken(shared)));
  77. EXPECT_TRUE(IsWorkletToken(blink::ExecutionContextToken(animation)));
  78. EXPECT_TRUE(IsWorkletToken(blink::ExecutionContextToken(audio)));
  79. EXPECT_TRUE(IsWorkletToken(blink::ExecutionContextToken(layout)));
  80. EXPECT_TRUE(IsWorkletToken(blink::ExecutionContextToken(paint)));
  81. }
  82. TEST_F(V8ContextTrackerHelpersTest, GetExecutionContext) {
  83. FrameNode* frame_node = mock_graph->frame.get();
  84. auto* execution_context =
  85. GetExecutionContext(frame_node->GetFrameToken(), graph());
  86. ASSERT_TRUE(execution_context);
  87. EXPECT_EQ(frame_node, execution_context->GetFrameNode());
  88. }
  89. TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionMainWorld) {
  90. TestNodeWrapper<FrameNodeImpl> child_frame(graph()->CreateFrameNodeAutoId(
  91. mock_graph->process.get(), mock_graph->page.get(),
  92. mock_graph->frame.get()));
  93. // A valid description of a main frame.
  94. auto desc = mojom::V8ContextDescription(
  95. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  96. /* world_name */ absl::nullopt, mock_graph->frame->frame_token());
  97. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  98. ValidateV8ContextDescription(desc));
  99. EXPECT_EQ(false,
  100. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  101. // A valid description of a cross-process child frame.
  102. desc = mojom::V8ContextDescription(
  103. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  104. /* world_name */ absl::nullopt, mock_graph->child_frame->frame_token());
  105. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  106. ValidateV8ContextDescription(desc));
  107. EXPECT_EQ(false,
  108. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  109. // A valid description of a same-process child frame.
  110. desc = mojom::V8ContextDescription(
  111. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  112. /* world_name */ absl::nullopt, child_frame->frame_token());
  113. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  114. ValidateV8ContextDescription(desc));
  115. EXPECT_EQ(true,
  116. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  117. // A valid description of a frame, but one that doesn't have a corresponding
  118. // entry in the graph. In this case its impossible to determine if
  119. // IframeAttributionData should accompany the V8ContextDescription.
  120. desc = mojom::V8ContextDescription(
  121. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  122. /* world_name */ absl::nullopt, blink::LocalFrameToken());
  123. EXPECT_EQ(absl::nullopt,
  124. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  125. // A main-world should not have a world name.
  126. EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorldName,
  127. ValidateV8ContextDescription(mojom::V8ContextDescription(
  128. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  129. kWorldName, mock_graph->frame->frame_token())));
  130. // A main world must have an |execution_context_token|.
  131. EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
  132. ValidateV8ContextDescription(mojom::V8ContextDescription(
  133. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  134. /* world_name */ absl::nullopt,
  135. /* execution_context_token */ absl::nullopt)));
  136. // A main world must have an blink::LocalFrameToken.
  137. blink::ExecutionContextToken worker_token((blink::SharedWorkerToken()));
  138. EXPECT_EQ(V8ContextDescriptionStatus::kMissingLocalFrameToken,
  139. ValidateV8ContextDescription(mojom::V8ContextDescription(
  140. blink::V8ContextToken(), mojom::V8ContextWorldType::kMain,
  141. /* world_name */ absl::nullopt, worker_token)));
  142. }
  143. TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionWorkerWorld) {
  144. blink::DedicatedWorkerToken worker_token;
  145. auto worker = TestNodeWrapper<WorkerNodeImpl>::Create(
  146. graph(), WorkerNode::WorkerType::kDedicated, mock_graph->process.get(),
  147. "browser_context", worker_token);
  148. // A valid worker description.
  149. auto desc = mojom::V8ContextDescription(
  150. blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
  151. /* world_name */ absl::nullopt, worker_token);
  152. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  153. ValidateV8ContextDescription(desc));
  154. EXPECT_EQ(false,
  155. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  156. // A worker should not have a world name.
  157. EXPECT_EQ(
  158. V8ContextDescriptionStatus::kUnexpectedWorldName,
  159. ValidateV8ContextDescription(mojom::V8ContextDescription(
  160. blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
  161. kWorldName, worker_token)));
  162. // A worker must have an |execution_context_token|.
  163. EXPECT_EQ(
  164. V8ContextDescriptionStatus::kMissingExecutionContextToken,
  165. ValidateV8ContextDescription(mojom::V8ContextDescription(
  166. blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
  167. /* world_name */ absl::nullopt,
  168. /* execution_context_token */ absl::nullopt)));
  169. // A worker must have a valid worker token, not a LocalFrameToken.
  170. EXPECT_EQ(
  171. V8ContextDescriptionStatus::kUnexpectedLocalFrameToken,
  172. ValidateV8ContextDescription(mojom::V8ContextDescription(
  173. blink::V8ContextToken(), mojom::V8ContextWorldType::kWorkerOrWorklet,
  174. /* world_name */ absl::nullopt, blink::LocalFrameToken())));
  175. }
  176. TEST_F(V8ContextTrackerHelpersTest,
  177. ValidateV8ContextDescriptionExtensionWorld) {
  178. // A valid extension description.
  179. auto desc = mojom::V8ContextDescription(
  180. blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
  181. kValidExtensionWorldName, mock_graph->frame->frame_token());
  182. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  183. ValidateV8ContextDescription(desc));
  184. EXPECT_EQ(false,
  185. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  186. // An extension must have a world name.
  187. EXPECT_EQ(
  188. V8ContextDescriptionStatus::kMissingWorldName,
  189. ValidateV8ContextDescription(mojom::V8ContextDescription(
  190. blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
  191. /* world_name */ absl::nullopt, mock_graph->frame->frame_token())));
  192. // An invalid extension name should fail.
  193. EXPECT_EQ(V8ContextDescriptionStatus::kInvalidExtensionWorldName,
  194. ValidateV8ContextDescription(mojom::V8ContextDescription(
  195. blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
  196. kInvalidExtensionWorldName, mock_graph->frame->frame_token())));
  197. // An extension must have an |execution_context_token|.
  198. EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
  199. ValidateV8ContextDescription(mojom::V8ContextDescription(
  200. blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
  201. kValidExtensionWorldName,
  202. /* execution_context_token */ absl::nullopt)));
  203. // An extension can't inject into a worklet.
  204. EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
  205. ValidateV8ContextDescription(mojom::V8ContextDescription(
  206. blink::V8ContextToken(), mojom::V8ContextWorldType::kExtension,
  207. kValidExtensionWorldName, blink::AudioWorkletToken())));
  208. }
  209. TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionIsolatedWorld) {
  210. // An isolated world may or may not have a |world_name|.
  211. auto desc = mojom::V8ContextDescription(
  212. blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
  213. /* world_name */ absl::nullopt, mock_graph->frame->frame_token());
  214. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  215. ValidateV8ContextDescription(desc));
  216. EXPECT_EQ(false,
  217. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  218. desc = mojom::V8ContextDescription(
  219. blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated, kWorldName,
  220. mock_graph->frame->frame_token());
  221. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  222. ValidateV8ContextDescription(desc));
  223. EXPECT_EQ(false,
  224. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  225. // An isolated world must have an |execution_context_token|
  226. EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
  227. ValidateV8ContextDescription(mojom::V8ContextDescription(
  228. blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
  229. /* world_name */ absl::nullopt,
  230. /* execution_context_token */ absl::nullopt)));
  231. // An isolated world can not inject into a worklet.
  232. EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
  233. ValidateV8ContextDescription(mojom::V8ContextDescription(
  234. blink::V8ContextToken(), mojom::V8ContextWorldType::kIsolated,
  235. /* world_name */ absl::nullopt, blink::AudioWorkletToken())));
  236. }
  237. TEST_F(V8ContextTrackerHelpersTest,
  238. ValidateV8ContextDescriptionInspectorWorld) {
  239. // A valid inspector world.
  240. auto desc = mojom::V8ContextDescription(
  241. blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
  242. /* world_name */ absl::nullopt, mock_graph->frame->frame_token());
  243. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  244. ValidateV8ContextDescription(desc));
  245. EXPECT_EQ(false,
  246. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  247. // An inspector world must have an |execution_context_token|
  248. EXPECT_EQ(V8ContextDescriptionStatus::kMissingExecutionContextToken,
  249. ValidateV8ContextDescription(mojom::V8ContextDescription(
  250. blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
  251. /* world_name */ absl::nullopt,
  252. /* execution_context_token */ absl::nullopt)));
  253. // An inspector world can not inject into a worklet.
  254. EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorkletToken,
  255. ValidateV8ContextDescription(mojom::V8ContextDescription(
  256. blink::V8ContextToken(), mojom::V8ContextWorldType::kInspector,
  257. /* world_name */ absl::nullopt, blink::AudioWorkletToken())));
  258. }
  259. TEST_F(V8ContextTrackerHelpersTest, ValidateV8ContextDescriptionRegExpWorld) {
  260. // A valid regexp world.
  261. auto desc = mojom::V8ContextDescription(
  262. blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
  263. /* world_name */ absl::nullopt,
  264. /* execution_context_token */ absl::nullopt);
  265. EXPECT_EQ(V8ContextDescriptionStatus::kValid,
  266. ValidateV8ContextDescription(desc));
  267. EXPECT_EQ(false,
  268. ExpectIframeAttributionDataForV8ContextDescription(desc, graph()));
  269. // A regexp world must not have a |world_name|.
  270. EXPECT_EQ(V8ContextDescriptionStatus::kUnexpectedWorldName,
  271. ValidateV8ContextDescription(mojom::V8ContextDescription(
  272. blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
  273. kWorldName,
  274. /* execution_context_token */ absl::nullopt)));
  275. // A regexp world must not have an |execution_context_token|.
  276. EXPECT_EQ(
  277. V8ContextDescriptionStatus::kUnexpectedExecutionContextToken,
  278. ValidateV8ContextDescription(mojom::V8ContextDescription(
  279. blink::V8ContextToken(), mojom::V8ContextWorldType::kRegExp,
  280. /* world_name */ absl::nullopt, mock_graph->frame->frame_token())));
  281. }
  282. } // namespace v8_memory
  283. } // namespace performance_manager