1 // Copyright 2013 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_WEB_TEST_BROWSER_WEB_TEST_CONTROL_HOST_H_ 6 #define CONTENT_WEB_TEST_BROWSER_WEB_TEST_CONTROL_HOST_H_ 7 8 #include <map> 9 #include <memory> 10 #include <ostream> 11 #include <set> 12 #include <string> 13 #include <utility> 14 #include <vector> 15 16 #include "base/cancelable_callback.h" 17 #include "base/files/file_path.h" 18 #include "base/files/scoped_temp_dir.h" 19 #include "base/macros.h" 20 #include "base/memory/weak_ptr.h" 21 #include "base/scoped_observer.h" 22 #include "base/sequence_checker.h" 23 #include "base/synchronization/lock.h" 24 #include "base/values.h" 25 #include "build/build_config.h" 26 #include "content/public/browser/bluetooth_chooser.h" 27 #include "content/public/browser/global_routing_id.h" 28 #include "content/public/browser/gpu_data_manager_observer.h" 29 #include "content/public/browser/notification_observer.h" 30 #include "content/public/browser/notification_registrar.h" 31 #include "content/public/browser/render_process_host.h" 32 #include "content/public/browser/render_process_host_observer.h" 33 #include "content/public/browser/web_contents_observer.h" 34 #include "content/web_test/browser/leak_detector.h" 35 #include "content/web_test/common/web_test.mojom.h" 36 #include "mojo/public/cpp/bindings/associated_receiver_set.h" 37 #include "mojo/public/cpp/bindings/associated_remote.h" 38 #include "third_party/blink/public/common/web_preferences/web_preferences.h" 39 #include "ui/gfx/geometry/size.h" 40 41 class SkBitmap; 42 43 namespace content { 44 class DevToolsProtocolTestBindings; 45 class RenderFrameHost; 46 class Shell; 47 class WebTestBluetoothChooserFactory; 48 class WebTestDevToolsBindings; 49 struct TestInfo; 50 51 class WebTestResultPrinter { 52 public: 53 WebTestResultPrinter(std::ostream* output, std::ostream* error); 54 ~WebTestResultPrinter() = default; 55 reset()56 void reset() { state_ = DURING_TEST; } output_finished()57 bool output_finished() const { return state_ == AFTER_TEST; } set_capture_text_only(bool capture_text_only)58 void set_capture_text_only(bool capture_text_only) { 59 capture_text_only_ = capture_text_only; 60 } 61 set_encode_binary_data(bool encode_binary_data)62 void set_encode_binary_data(bool encode_binary_data) { 63 encode_binary_data_ = encode_binary_data; 64 } 65 66 void PrintTextHeader(); 67 void PrintTextBlock(const std::string& block); 68 void PrintTextFooter(); 69 70 void PrintImageHeader(const std::string& actual_hash, 71 const std::string& expected_hash); 72 void PrintImageBlock(const std::vector<unsigned char>& png_image); 73 void PrintImageFooter(); 74 75 void PrintAudioHeader(); 76 void PrintAudioBlock(const std::vector<unsigned char>& audio_data); 77 void PrintAudioFooter(); 78 79 void AddMessageToStderr(const std::string& message); 80 void AddMessage(const std::string& message); 81 void AddMessageRaw(const std::string& message); 82 void AddErrorMessage(const std::string& message); 83 84 void CloseStderr(); 85 void StartStateDump(); 86 87 private: 88 void PrintEncodedBinaryData(const std::vector<unsigned char>& data); 89 90 enum State { 91 DURING_TEST, 92 DURING_STATE_DUMP, 93 IN_TEXT_BLOCK, 94 IN_AUDIO_BLOCK, 95 IN_IMAGE_BLOCK, 96 AFTER_TEST 97 }; 98 State state_; 99 100 bool capture_text_only_; 101 bool encode_binary_data_; 102 103 std::ostream* output_; 104 std::ostream* error_; 105 106 DISALLOW_COPY_AND_ASSIGN(WebTestResultPrinter); 107 }; 108 109 class WebTestControlHost : public WebContentsObserver, 110 public RenderProcessHostObserver, 111 public GpuDataManagerObserver, 112 public mojom::WebTestControlHost { 113 public: 114 static WebTestControlHost* Get(); 115 116 WebTestControlHost(); 117 ~WebTestControlHost() override; 118 119 WebTestControlHost(const WebTestControlHost&) = delete; 120 WebTestControlHost& operator=(const WebTestControlHost&) = delete; 121 122 // True if the controller is ready for testing. 123 bool PrepareForWebTest(const TestInfo& test_info); 124 // True if the controller was reset successfully. 125 bool ResetBrowserAfterWebTest(); 126 127 // Allows WebTestControlHost to track all WebContents created by tests, either 128 // by Javascript or by C++ code in the browser. 129 void DidCreateOrAttachWebContents(WebContents* web_contents); 130 131 void SetTempPath(const base::FilePath& temp_path); 132 void OverrideWebkitPrefs(blink::web_pref::WebPreferences* prefs); 133 void OpenURL(const GURL& url); 134 bool IsMainWindow(WebContents* web_contents) const; 135 std::unique_ptr<BluetoothChooser> RunBluetoothChooser( 136 RenderFrameHost* frame, 137 const BluetoothChooser::EventHandler& event_handler); 138 void RequestToLockMouse(WebContents* web_contents); 139 printer()140 WebTestResultPrinter* printer() { return printer_.get(); } set_printer(WebTestResultPrinter * printer)141 void set_printer(WebTestResultPrinter* printer) { printer_.reset(printer); } 142 143 void DevToolsProcessCrashed(); 144 145 // Called when a renderer wants to bind a connection to the 146 // WebTestControlHost. 147 void BindWebTestControlHostForRenderer( 148 int render_process_id, 149 mojo::PendingAssociatedReceiver<mojom::WebTestControlHost> receiver); 150 151 // WebContentsObserver implementation. 152 void PluginCrashed(const base::FilePath& plugin_path, 153 base::ProcessId plugin_pid) override; 154 void TitleWasSet(NavigationEntry* entry) override; 155 void DidFailLoad(RenderFrameHost* render_frame_host, 156 const GURL& validated_url, 157 int error_code) override; 158 void WebContentsDestroyed() override; 159 void DidUpdateFaviconURL( 160 RenderFrameHost* render_frame_host, 161 const std::vector<blink::mojom::FaviconURLPtr>& candidates) override; 162 void RenderViewHostChanged(RenderViewHost* old_host, 163 RenderViewHost* new_host) override; 164 void RenderViewDeleted(RenderViewHost* render_view_host) override; 165 void DidFinishNavigation(NavigationHandle* navigation_handle) override; 166 167 // RenderProcessHostObserver implementation. 168 void RenderProcessHostDestroyed( 169 RenderProcessHost* render_process_host) override; 170 void RenderProcessExited(RenderProcessHost* render_process_host, 171 const ChildProcessTerminationInfo& info) override; 172 173 // GpuDataManagerObserver implementation. 174 void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; 175 accumulated_web_test_runtime_flags_changes()176 const base::DictionaryValue& accumulated_web_test_runtime_flags_changes() 177 const { 178 return accumulated_web_test_runtime_flags_changes_; 179 } 180 181 private: 182 enum TestPhase { BETWEEN_TESTS, DURING_TEST, CLEAN_UP }; 183 184 // Node structure to construct a RenderFrameHost tree. 185 struct Node { 186 explicit Node(RenderFrameHost* host); 187 ~Node(); 188 189 Node(Node&& other); 190 Node& operator=(Node&& other); 191 192 RenderFrameHost* render_frame_host = nullptr; 193 GlobalFrameRoutingId render_frame_host_id; 194 std::vector<Node*> children; 195 }; 196 197 class WebTestWindowObserver; 198 199 static WebTestControlHost* instance_; 200 201 // WebTestControlHost implementation. 202 void InitiateCaptureDump( 203 mojom::WebTestRendererDumpResultPtr renderer_dump_result, 204 bool capture_navigation_history, 205 bool capture_pixels) override; 206 void TestFinishedInSecondaryRenderer() override; 207 void PrintMessageToStderr(const std::string& message) override; 208 void PrintMessage(const std::string& message) override; 209 void Reload() override; 210 void OverridePreferences( 211 const blink::web_pref::WebPreferences& web_preferences) override; 212 void SetMainWindowHidden(bool hidden) override; 213 void CheckForLeakedWindows() override; 214 void GoToOffset(int offset) override; 215 void SendBluetoothManualChooserEvent(const std::string& event, 216 const std::string& argument) override; 217 void SetBluetoothManualChooser(bool enable) override; 218 void GetBluetoothManualChooserEvents( 219 GetBluetoothManualChooserEventsCallback reply) override; 220 void SetPopupBlockingEnabled(bool block_popups) override; 221 void LoadURLForFrame(const GURL& url, const std::string& frame_name) override; 222 void SetScreenOrientationChanged() override; 223 void SetPermission(const std::string& name, 224 blink::mojom::PermissionStatus status, 225 const GURL& origin, 226 const GURL& embedding_origin) override; 227 void BlockThirdPartyCookies(bool block) override; 228 void GetWritableDirectory(GetWritableDirectoryCallback reply) override; 229 void SetFilePathForMockFileDialog(const base::FilePath& path) override; 230 void FocusDevtoolsSecondaryWindow() override; 231 void SetTrustTokenKeyCommitments(const std::string& raw_commitments, 232 base::OnceClosure callback) override; 233 void ClearTrustTokenState(base::OnceClosure callback) override; 234 void SetDatabaseQuota(int32_t quota) override; 235 void ClearAllDatabases() override; 236 void SimulateWebNotificationClick( 237 const std::string& title, 238 int32_t action_index, 239 const base::Optional<base::string16>& reply) override; 240 void SimulateWebNotificationClose(const std::string& title, 241 bool by_user) override; 242 void SimulateWebContentIndexDelete(const std::string& id) override; 243 void WebTestRuntimeFlagsChanged( 244 base::Value changed_web_test_runtime_flags) override; 245 void RegisterIsolatedFileSystem( 246 const std::vector<base::FilePath>& file_paths, 247 RegisterIsolatedFileSystemCallback callback) override; 248 void DropPointerLock() override; 249 void SetPointerLockWillFail() override; 250 void SetPointerLockWillRespondAsynchronously() override; 251 void AllowPointerLock() override; 252 void WorkItemAdded(mojom::WorkItemPtr work_item) override; 253 void RequestWorkItem() override; 254 void WorkQueueStatesChanged(base::Value changed_work_queue_states) override; 255 256 void DiscardMainWindow(); 257 void CloseTestOpenedWindows(); 258 259 // Makes sure that the potentially new renderer associated with |frame| is 1) 260 // initialized for the test, 2) kept up to date wrt test flags and 3) 261 // monitored for crashes. 262 void HandleNewRenderFrameHost(RenderFrameHost* frame); 263 264 // Message handlers. 265 void OnAudioDump(const std::vector<unsigned char>& audio_dump); 266 void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image); 267 void OnTextDump(const std::string& dump); 268 void OnDumpFrameLayoutResponse(int frame_tree_node_id, 269 const std::string& dump); 270 void OnTestFinished(); 271 void OnCaptureSessionHistory(); 272 void OnLeakDetectionDone(int pid, 273 const LeakDetector::LeakDetectionReport& report); 274 275 // At the end of the test, once browser-side cleanup is done, commence reset 276 // of the renderer process that will stick around. 277 void ResetRendererAfterWebTest(); 278 // Callback for when the renderer completes its reset at the end of the test. 279 void ResetRendererAfterWebTestDone(); 280 void OnPixelDumpCaptured(const SkBitmap& snapshot); 281 void ReportResults(); 282 void EnqueueSurfaceCopyRequest(); 283 284 mojo::AssociatedRemote<mojom::WebTestRenderFrame>& 285 GetWebTestRenderFrameRemote(RenderFrameHost* frame); 286 mojo::AssociatedRemote<mojom::WebTestRenderThread>& 287 GetWebTestRenderThreadRemote(RenderProcessHost* process); 288 void HandleWebTestRenderFrameRemoteError(const GlobalFrameRoutingId& key); 289 void HandleWebTestRenderThreadRemoteError(RenderProcessHost* key); 290 291 // CompositeAllFramesThen() first builds a frame tree based on 292 // frame->GetParent(). Then, it builds a queue of frames in depth-first order, 293 // so that compositing happens from the leaves up. Finally, 294 // CompositeNodeQueueThen() is used to composite one frame at a time, 295 // asynchronously, continuing on to the next frame once each composite 296 // finishes. Once all nodes have been composited, the final callback is run. 297 // Each call to CompositeWithRaster() is an asynchronous Mojo call, to avoid 298 // reentrancy problems. 299 void CompositeAllFramesThen(base::OnceCallback<void()> callback); 300 301 private: 302 Node* BuildFrameTree(WebContents* web_contents); 303 void CompositeNodeQueueThen(base::OnceCallback<void()> callback); 304 void BuildDepthFirstQueue(Node* node); 305 306 #if defined(OS_MAC) 307 // Bypasses system APIs to force a resize on the RenderWidgetHostView when in 308 // headless web tests. 309 static void PlatformResizeWindowMac(Shell* shell, const gfx::Size& size); 310 #endif 311 312 public: 313 std::unique_ptr<WebTestResultPrinter> printer_; 314 315 base::FilePath current_working_directory_; 316 base::FilePath temp_path_; 317 318 Shell* main_window_; 319 Shell* secondary_window_; 320 321 std::unique_ptr<WebTestDevToolsBindings> devtools_bindings_; 322 std::unique_ptr<DevToolsProtocolTestBindings> 323 devtools_protocol_test_bindings_; 324 325 // What phase of running an individual test we are currently in. 326 TestPhase test_phase_; 327 328 // Per test config. 329 std::string expected_pixel_hash_; 330 GURL test_url_; 331 bool protocol_mode_; 332 333 // Stores the default test-adapted WebPreferences which is then used to fully 334 // reset the main window's preferences if and when it is reused. 335 blink::web_pref::WebPreferences default_prefs_; 336 337 // True if the WebPreferences of newly created RenderViewHost should be 338 // overridden with prefs_. 339 bool should_override_prefs_; 340 blink::web_pref::WebPreferences prefs_; 341 342 bool crash_when_leak_found_; 343 std::unique_ptr<LeakDetector> leak_detector_; 344 345 std::unique_ptr<WebTestBluetoothChooserFactory> bluetooth_chooser_factory_; 346 347 // Observe windows opened by tests. 348 base::flat_map<WebContents*, std::unique_ptr<WebTestWindowObserver>> 349 test_opened_window_observers_; 350 351 // Renderer processes are observed to detect crashes. 352 ScopedObserver<RenderProcessHost, RenderProcessHostObserver> 353 render_process_host_observer_{this}; 354 std::set<RenderProcessHost*> all_observed_render_process_hosts_; 355 std::set<RenderProcessHost*> main_window_render_process_hosts_; 356 std::set<RenderViewHost*> main_window_render_view_hosts_; 357 358 // Changes reported by WebTestRuntimeFlagsChanged() that have accumulated 359 // since PrepareForWebTest (i.e. changes that need to be sent to a fresh 360 // renderer created while test is in progress). 361 base::DictionaryValue accumulated_web_test_runtime_flags_changes_; 362 363 // Work items to be processed in the TestRunner on the renderer process 364 // that hosts the main window's main frame. 365 base::circular_deque<mojom::WorkItemPtr> work_queue_; 366 367 // Properties of the work queue. 368 base::DictionaryValue work_queue_states_; 369 370 mojom::WebTestRendererDumpResultPtr renderer_dump_result_; 371 std::string navigation_history_dump_; 372 base::Optional<SkBitmap> pixel_dump_; 373 base::Optional<std::string> layout_dump_; 374 std::string actual_pixel_hash_; 375 // By default a test that opens other windows will have them closed at the end 376 // of the test before checking for leaks. It may specify that it has closed 377 // any windows it opened, and thus look for leaks from them with this flag. 378 bool check_for_leaked_windows_ = false; 379 bool waiting_for_pixel_results_ = false; 380 int waiting_for_layout_dumps_ = 0; 381 382 // Map from frame_tree_node_id into frame-specific dumps while collecting 383 // text dumps from all frames, before stitching them together. 384 std::map<int, std::string> frame_to_layout_dump_map_; 385 386 std::vector<std::unique_ptr<Node>> composite_all_frames_node_storage_; 387 std::queue<Node*> composite_all_frames_node_queue_; 388 389 // Map from one frame to one mojo pipe. 390 std::map<GlobalFrameRoutingId, 391 mojo::AssociatedRemote<mojom::WebTestRenderFrame>> 392 web_test_render_frame_map_; 393 394 std::map<RenderProcessHost*, 395 mojo::AssociatedRemote<mojom::WebTestRenderThread>> 396 web_test_render_thread_map_; 397 398 // The set of bindings that receive messages on the mojom::WebTestControlHost 399 // interface from renderer processes. There should be one per renderer 400 // process, and we store it with the |render_process_id| attached to it 401 // so that we can tell where a given message came from if needed. 402 mojo::AssociatedReceiverSet<mojom::WebTestControlHost, 403 int /*render_process_id*/> 404 receiver_bindings_; 405 406 base::ScopedTempDir writable_directory_for_tests_; 407 408 enum class NextPointerLockAction { 409 kWillSucceed, 410 kTestWillRespond, 411 kWillFail, 412 }; 413 NextPointerLockAction next_pointer_lock_action_ = 414 NextPointerLockAction::kWillSucceed; 415 416 SEQUENCE_CHECKER(sequence_checker_); 417 418 base::WeakPtrFactory<WebTestControlHost> weak_factory_{this}; 419 }; 420 421 } // namespace content 422 423 #endif // CONTENT_WEB_TEST_BROWSER_WEB_TEST_CONTROL_HOST_H_ 424