1 // Copyright 2014 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 5 #ifndef CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_ 6 #define CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_ 7 8 // A collection of functions designed for use with content_shell based browser 9 // tests internal to the content/ module. 10 // Note: If a function here also works with browser_tests, it should be in 11 // the content public API. 12 13 #include <memory> 14 #include <string> 15 #include <vector> 16 17 #include "base/compiler_specific.h" 18 #include "base/files/file_path.h" 19 #include "base/macros.h" 20 #include "base/memory/weak_ptr.h" 21 #include "base/optional.h" 22 #include "base/run_loop.h" 23 #include "build/build_config.h" 24 #include "content/browser/bad_message.h" 25 #include "content/common/frame_messages.h" 26 #include "content/public/browser/devtools_agent_host.h" 27 #include "content/public/browser/javascript_dialog_manager.h" 28 #include "content/public/browser/web_contents_delegate.h" 29 #include "content/public/test/browser_test_utils.h" 30 #include "content/public/test/test_utils.h" 31 #include "mojo/public/cpp/bindings/pending_remote.h" 32 #include "third_party/blink/public/mojom/choosers/file_chooser.mojom-forward.h" 33 #include "third_party/blink/public/mojom/choosers/popup_menu.mojom.h" 34 #include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h" 35 #include "url/gurl.h" 36 37 namespace content { 38 39 class FrameTreeNode; 40 class RenderFrameHost; 41 class RenderFrameHostImpl; 42 class RenderWidgetHostImpl; 43 class Shell; 44 class SiteInstance; 45 class ToRenderFrameHost; 46 47 // Navigates the frame represented by |node| to |url|, blocking until the 48 // navigation finishes. Returns true if the navigation succeedd and the final 49 // URL matches |url|. 50 bool NavigateFrameToURL(FrameTreeNode* node, const GURL& url); 51 52 // Sets the DialogManager to proceed by default or not when showing a 53 // BeforeUnload dialog, and if it proceeds, what value to return. 54 void SetShouldProceedOnBeforeUnload(Shell* shell, bool proceed, bool success); 55 56 // Extends the ToRenderFrameHost mechanism to FrameTreeNodes. 57 RenderFrameHost* ConvertToRenderFrameHost(FrameTreeNode* frame_tree_node); 58 59 // Helper function to navigate a window to a |url|, using a browser-initiated 60 // navigation that will stay in the same BrowsingInstance. Most 61 // browser-initiated navigations swap BrowsingInstances, but some tests need a 62 // navigation to swap processes for cross-site URLs (even outside of 63 // --site-per-process) while staying in the same BrowsingInstance. 64 WARN_UNUSED_RESULT bool NavigateToURLInSameBrowsingInstance(Shell* window, 65 const GURL& url); 66 67 // Creates compact textual representations of the state of the frame tree that 68 // is appropriate for use in assertions. 69 // 70 // The diagrams show frame tree structure, the SiteInstance of current frames, 71 // presence of pending frames, and the SiteInstances of any and all proxies. 72 // They look like this: 73 // 74 // Site A (D pending) -- proxies for B C 75 // |--Site B --------- proxies for A C 76 // +--Site C --------- proxies for B A 77 // |--Site A ---- proxies for B 78 // +--Site A ---- proxies for B 79 // +--Site A -- proxies for B 80 // Where A = http://127.0.0.1/ 81 // B = http://foo.com/ (no process) 82 // C = http://bar.com/ 83 // D = http://next.com/ 84 // 85 // SiteInstances are assigned single-letter names (A, B, C) which are remembered 86 // across invocations of the pretty-printer. 87 class FrameTreeVisualizer { 88 public: 89 FrameTreeVisualizer(); 90 ~FrameTreeVisualizer(); 91 92 // Formats and returns a diagram for the provided FrameTreeNode. 93 std::string DepictFrameTree(FrameTreeNode* root); 94 95 private: 96 // Assign or retrive the abbreviated short name (A, B, C) for a site instance. 97 std::string GetName(SiteInstance* site_instance); 98 99 // Elements are site instance ids. The index of the SiteInstance in the vector 100 // determines the abbreviated name (0->A, 1->B) for that SiteInstance. 101 std::vector<int> seen_site_instance_ids_; 102 103 DISALLOW_COPY_AND_ASSIGN(FrameTreeVisualizer); 104 }; 105 106 // Uses window.open to open a popup from the frame |opener| with the specified 107 // |url|, |name| and window |features|. |expect_return_from_window_open| is used 108 // to indicate if the caller expects window.open() to return a non-null value. 109 // Waits for the navigation to |url| to finish and then returns the new popup's 110 // Shell. Note that since this navigation to |url| is renderer-initiated, it 111 // won't cause a process swap unless used in --site-per-process mode. 112 Shell* OpenPopup(const ToRenderFrameHost& opener, 113 const GURL& url, 114 const std::string& name, 115 const std::string& features, 116 bool expect_return_from_window_open); 117 118 // Same as above, but with an empty |features| and 119 // |expect_return_from_window_open| assumed to be true.. 120 Shell* OpenPopup(const ToRenderFrameHost& opener, 121 const GURL& url, 122 const std::string& name); 123 124 // Helper for mocking choosing a file via a file dialog. 125 class FileChooserDelegate : public WebContentsDelegate { 126 public: 127 // Constructs a WebContentsDelegate that mocks a file dialog. 128 // The mocked file dialog will always reply that the user selected |file|. 129 // |callback| is invoked when RunFileChooser() is called. 130 FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback); 131 ~FileChooserDelegate() override; 132 133 // Implementation of WebContentsDelegate::RunFileChooser. 134 void RunFileChooser(RenderFrameHost* render_frame_host, 135 scoped_refptr<content::FileSelectListener> listener, 136 const blink::mojom::FileChooserParams& params) override; 137 138 // The params passed to RunFileChooser. params()139 const blink::mojom::FileChooserParams& params() const { return *params_; } 140 141 private: 142 base::FilePath file_; 143 base::OnceClosure callback_; 144 blink::mojom::FileChooserParamsPtr params_; 145 }; 146 147 // This class is a TestNavigationManager that only monitors notifications within 148 // the given frame tree node. 149 class FrameTestNavigationManager : public TestNavigationManager { 150 public: 151 FrameTestNavigationManager(int frame_tree_node_id, 152 WebContents* web_contents, 153 const GURL& url); 154 155 private: 156 // TestNavigationManager: 157 bool ShouldMonitorNavigation(NavigationHandle* handle) override; 158 159 // Notifications are filtered so only this frame is monitored. 160 int filtering_frame_tree_node_id_; 161 162 DISALLOW_COPY_AND_ASSIGN(FrameTestNavigationManager); 163 }; 164 165 // An observer that can wait for a specific URL to be committed in a specific 166 // frame. 167 // Note: it does not track the start of a navigation, unlike other observers. 168 class UrlCommitObserver : WebContentsObserver { 169 public: 170 explicit UrlCommitObserver(FrameTreeNode* frame_tree_node, const GURL& url); 171 ~UrlCommitObserver() override; 172 173 void Wait(); 174 175 private: 176 void DidFinishNavigation(NavigationHandle* navigation_handle) override; 177 178 // The id of the FrameTreeNode in which navigations are peformed. 179 int frame_tree_node_id_; 180 181 // The URL this observer is expecting to be committed. 182 GURL url_; 183 184 // The RunLoop used to spin the message loop. 185 base::RunLoop run_loop_; 186 187 DISALLOW_COPY_AND_ASSIGN(UrlCommitObserver); 188 }; 189 190 // Waits for a kill of the given RenderProcessHost and returns the 191 // BadMessageReason that caused a //content-triggerred kill. 192 // 193 // Example usage: 194 // RenderProcessHostBadIpcMessageWaiter kill_waiter(render_process_host); 195 // ... test code that triggers a renderer kill ... 196 // EXPECT_EQ(bad_message::RFH_INVALID_ORIGIN_ON_COMMIT, kill_waiter.Wait()); 197 // 198 // Tests that don't expect kills (e.g. tests where a renderer process exits 199 // normally, like RenderFrameHostManagerTest.ProcessExitWithSwappedOutViews) 200 // should use RenderProcessHostWatcher instead of 201 // RenderProcessHostBadIpcMessageWaiter. 202 class RenderProcessHostBadIpcMessageWaiter { 203 public: 204 explicit RenderProcessHostBadIpcMessageWaiter( 205 RenderProcessHost* render_process_host); 206 207 // Waits until the renderer process exits. Returns the bad message that made 208 // //content kill the renderer. |base::nullopt| is returned if the renderer 209 // was killed outside of //content or exited normally. 210 base::Optional<bad_message::BadMessageReason> Wait() WARN_UNUSED_RESULT; 211 212 private: 213 RenderProcessHostKillWaiter internal_waiter_; 214 215 DISALLOW_COPY_AND_ASSIGN(RenderProcessHostBadIpcMessageWaiter); 216 }; 217 218 class ShowPopupWidgetWaiter 219 : public WebContentsObserver, 220 public blink::mojom::PopupWidgetHostInterceptorForTesting { 221 public: 222 ShowPopupWidgetWaiter(WebContents* web_contents, 223 RenderFrameHostImpl* frame_host); 224 ~ShowPopupWidgetWaiter() override; 225 last_initial_rect()226 gfx::Rect last_initial_rect() const { return initial_rect_; } 227 last_routing_id()228 int last_routing_id() const { return routing_id_; } 229 230 // Waits until a popup request is received. 231 void Wait(); 232 233 // Stops observing new messages. 234 void Stop(); 235 236 private: 237 238 // WebContentsObserver: 239 #if defined(OS_MAC) || defined(OS_ANDROID) 240 bool ShowPopupMenu( 241 RenderFrameHost* render_frame_host, 242 mojo::PendingRemote<blink::mojom::PopupMenuClient>* popup_client, 243 const gfx::Rect& bounds, 244 int32_t item_height, 245 double font_size, 246 int32_t selected_item, 247 std::vector<blink::mojom::MenuItemPtr>* menu_items, 248 bool right_aligned, 249 bool allow_multiple_selection) override; 250 #endif 251 252 // Callback bound for creating a popup widget. 253 void DidCreatePopupWidget(RenderWidgetHostImpl* render_widget_host); 254 255 // blink::mojom::PopupWidgetHostInterceptorForTesting: 256 blink::mojom::PopupWidgetHost* GetForwardingInterface() override; 257 void ShowPopup(const gfx::Rect& initial_rect, 258 ShowPopupCallback callback) override; 259 260 base::RunLoop run_loop_; 261 gfx::Rect initial_rect_; 262 int32_t routing_id_ = MSG_ROUTING_NONE; 263 int32_t process_id_ = 0; 264 RenderFrameHostImpl* frame_host_; 265 266 DISALLOW_COPY_AND_ASSIGN(ShowPopupWidgetWaiter); 267 }; 268 269 // A BrowserMessageFilter that drops a blacklisted message. 270 class DropMessageFilter : public BrowserMessageFilter { 271 public: 272 DropMessageFilter(uint32_t message_class, uint32_t drop_message_id); 273 274 protected: 275 ~DropMessageFilter() override; 276 277 private: 278 // BrowserMessageFilter: 279 bool OnMessageReceived(const IPC::Message& message) override; 280 281 const uint32_t drop_message_id_; 282 283 DISALLOW_COPY_AND_ASSIGN(DropMessageFilter); 284 }; 285 286 // A BrowserMessageFilter that observes a message without handling it, and 287 // reports when it was seen. 288 class ObserveMessageFilter : public BrowserMessageFilter { 289 public: 290 ObserveMessageFilter(uint32_t message_class, uint32_t watch_message_id); 291 has_received_message()292 bool has_received_message() { return received_; } 293 294 // Spins a RunLoop until the message is observed. 295 void Wait(); 296 297 protected: 298 ~ObserveMessageFilter() override; 299 300 // BrowserMessageFilter: 301 bool OnMessageReceived(const IPC::Message& message) override; 302 303 private: 304 void QuitWait(); 305 306 const uint32_t watch_message_id_; 307 bool received_ = false; 308 base::OnceClosure quit_closure_; 309 310 DISALLOW_COPY_AND_ASSIGN(ObserveMessageFilter); 311 }; 312 313 // This observer waits until WebContentsObserver::OnRendererUnresponsive 314 // notification. 315 class UnresponsiveRendererObserver : public WebContentsObserver { 316 public: 317 explicit UnresponsiveRendererObserver(WebContents* web_contents); 318 ~UnresponsiveRendererObserver() override; 319 320 RenderProcessHost* Wait(base::TimeDelta timeout = base::TimeDelta::Max()); 321 322 private: 323 // WebContentsObserver: 324 void OnRendererUnresponsive(RenderProcessHost* render_process_host) override; 325 326 RenderProcessHost* captured_render_process_host_ = nullptr; 327 base::RunLoop run_loop_; 328 329 DISALLOW_COPY_AND_ASSIGN(UnresponsiveRendererObserver); 330 }; 331 332 // Helper class that overrides the JavaScriptDialogManager of a WebContents 333 // to endlessly block on beforeunload. 334 class BeforeUnloadBlockingDelegate : public JavaScriptDialogManager, 335 public WebContentsDelegate { 336 public: 337 explicit BeforeUnloadBlockingDelegate(WebContentsImpl* web_contents); 338 ~BeforeUnloadBlockingDelegate() override; 339 void Wait(); 340 341 // WebContentsDelegate 342 343 JavaScriptDialogManager* GetJavaScriptDialogManager( 344 WebContents* source) override; 345 346 // JavaScriptDialogManager 347 348 void RunJavaScriptDialog(WebContents* web_contents, 349 RenderFrameHost* render_frame_host, 350 JavaScriptDialogType dialog_type, 351 const base::string16& message_text, 352 const base::string16& default_prompt_text, 353 DialogClosedCallback callback, 354 bool* did_suppress_message) override; 355 356 void RunBeforeUnloadDialog(WebContents* web_contents, 357 RenderFrameHost* render_frame_host, 358 bool is_reload, 359 DialogClosedCallback callback) override; 360 361 bool HandleJavaScriptDialog(WebContents* web_contents, 362 bool accept, 363 const base::string16* prompt_override) override; 364 CancelDialogs(WebContents * web_contents,bool reset_state)365 void CancelDialogs(WebContents* web_contents, bool reset_state) override {} 366 367 private: 368 WebContentsImpl* web_contents_; 369 370 DialogClosedCallback callback_; 371 372 std::unique_ptr<base::RunLoop> run_loop_ = std::make_unique<base::RunLoop>(); 373 374 DISALLOW_COPY_AND_ASSIGN(BeforeUnloadBlockingDelegate); 375 }; 376 377 // A helper class to get DevTools inspector log messages (e.g. network errors). 378 class DevToolsInspectorLogWatcher : public DevToolsAgentHostClient { 379 public: 380 explicit DevToolsInspectorLogWatcher(WebContents* web_contents); 381 ~DevToolsInspectorLogWatcher() override; 382 383 void FlushAndStopWatching(); last_message()384 std::string last_message() { return last_message_; } 385 386 // DevToolsAgentHostClient: 387 void DispatchProtocolMessage(DevToolsAgentHost* host, 388 base::span<const uint8_t> message) override; 389 void AgentHostClosed(DevToolsAgentHost* host) override; 390 391 private: 392 scoped_refptr<DevToolsAgentHost> host_; 393 base::RunLoop run_loop_enable_log_; 394 base::RunLoop run_loop_disable_log_; 395 std::string last_message_; 396 }; 397 398 } // namespace content 399 400 #endif // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_ 401