| // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_PRERENDER_TEST_UTILS_H_ |
| #define CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_PRERENDER_TEST_UTILS_H_ |
| |
| #include <functional> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/circular_deque.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/scoped_multi_source_observation.h" |
| #include "base/synchronization/lock.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "chrome/browser/external_protocol/external_protocol_handler.h" |
| #include "chrome/browser/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h" |
| #include "chrome/browser/safe_browsing/test_safe_browsing_service.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h" |
| #include "components/no_state_prefetch/browser/no_state_prefetch_contents_delegate.h" |
| #include "components/no_state_prefetch/browser/no_state_prefetch_manager.h" |
| #include "components/safe_browsing/core/browser/db/fake_database_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_widget_host_observer.h" |
| #include "url/gurl.h" |
| |
| namespace prerender { |
| |
| namespace test_utils { |
| |
| class TestNoStatePrefetchContents : public NoStatePrefetchContents, |
| public content::RenderWidgetHostObserver { |
| public: |
| TestNoStatePrefetchContents( |
| NoStatePrefetchManager* no_state_prefetch_manager, |
| content::BrowserContext* browser_context, |
| const GURL& url, |
| const content::Referrer& referrer, |
| const absl::optional<url::Origin>& initiator_origin, |
| Origin origin, |
| FinalStatus expected_final_status, |
| bool ignore_final_status); |
| |
| TestNoStatePrefetchContents(const TestNoStatePrefetchContents&) = delete; |
| TestNoStatePrefetchContents& operator=(const TestNoStatePrefetchContents&) = |
| delete; |
| |
| ~TestNoStatePrefetchContents() override; |
| |
| bool CheckURL(const GURL& url) override; |
| |
| // For tests which do not know whether the no-state prefetcher will be used. |
| void set_skip_final_checks(bool value) { skip_final_checks_ = value; } |
| |
| FinalStatus expected_final_status() const { return expected_final_status_; } |
| |
| private: |
| // WebContentsObserver overrides. |
| void RenderFrameHostChanged( |
| content::RenderFrameHost* old_frame_host, |
| content::RenderFrameHost* new_frame_host) override; |
| |
| // RenderWidgetHostObserver overrides. |
| void RenderWidgetHostVisibilityChanged(content::RenderWidgetHost* widget_host, |
| bool became_visible) override; |
| void RenderWidgetHostDestroyed( |
| content::RenderWidgetHost* widget_host) override; |
| |
| FinalStatus expected_final_status_; |
| |
| base::ScopedMultiSourceObservation<content::RenderWidgetHost, |
| content::RenderWidgetHostObserver> |
| observations_{this}; |
| |
| // The main frame created for the prerender, if any. |
| raw_ptr<content::RenderFrameHost> new_main_frame_ = nullptr; |
| |
| // If true, |expected_final_status_| and other shutdown checks are skipped. |
| bool skip_final_checks_; |
| }; |
| |
| // A handle to a TestNoStatePrefetchContents whose lifetime is under the |
| // caller's control. A NoStatePrefetchContents may be destroyed at any point. |
| // This allows tracking the FinalStatus. |
| class TestPrerender : public NoStatePrefetchContents::Observer, |
| public base::SupportsWeakPtr<TestPrerender> { |
| public: |
| TestPrerender(); |
| |
| TestPrerender(const TestPrerender&) = delete; |
| TestPrerender& operator=(const TestPrerender&) = delete; |
| |
| ~TestPrerender() override; |
| |
| TestNoStatePrefetchContents* contents() const { return contents_; } |
| int number_of_loads() const { return number_of_loads_; } |
| FinalStatus GetFinalStatus() const; |
| |
| void WaitForCreate(); |
| void WaitForStart(); |
| void WaitForStop(); |
| |
| // Waits for |number_of_loads()| to be at least |expected_number_of_loads| OR |
| // for the prerender to stop running (just to avoid a timeout if the prerender |
| // dies). Note: this does not assert equality on the number of loads; the |
| // caller must do it instead. |
| void WaitForLoads(int expected_number_of_loads); |
| |
| void OnPrefetchContentsCreated(TestNoStatePrefetchContents* contents); |
| |
| // NoStatePrefetchContents::Observer implementation: |
| void OnPrefetchStart(NoStatePrefetchContents* contents) override; |
| |
| void OnPrefetchStopLoading(NoStatePrefetchContents* contents) override; |
| |
| void OnPrefetchStop(NoStatePrefetchContents* contents) override; |
| |
| private: |
| raw_ptr<TestNoStatePrefetchContents> contents_; |
| FinalStatus final_status_; |
| int number_of_loads_; |
| |
| int expected_number_of_loads_; |
| std::unique_ptr<base::RunLoop> load_waiter_; |
| |
| bool started_; |
| bool stopped_; |
| |
| base::RunLoop create_loop_; |
| base::RunLoop start_loop_; |
| base::RunLoop stop_loop_; |
| }; |
| |
| // Blocks until a TestNoStatePrefetchContents has been destroyed with the given |
| // final status. Should be created with a TestNoStatePrefetchContents, and then |
| // WaitForDestroy should be called and its return value checked. |
| class DestructionWaiter { |
| public: |
| // Does not own the no_state_prefetch_contents, which must outlive any call to |
| // WaitForDestroy(). |
| DestructionWaiter(TestNoStatePrefetchContents* no_state_prefetch_contents, |
| FinalStatus expected_final_status); |
| |
| DestructionWaiter(const DestructionWaiter&) = delete; |
| DestructionWaiter& operator=(const DestructionWaiter&) = delete; |
| |
| ~DestructionWaiter(); |
| |
| // Returns true if the TestNoStatePrefetchContents was destroyed with the |
| // correct final status, or false otherwise. Note this also may hang if the |
| // contents is never destroyed (which will presumably cause the test to time |
| // out). |
| bool WaitForDestroy(); |
| |
| private: |
| class DestructionMarker : public NoStatePrefetchContents::Observer { |
| public: |
| // Does not own the waiter which must outlive the |
| // TestNoStatePrefetchContents. |
| explicit DestructionMarker(DestructionWaiter* waiter); |
| |
| DestructionMarker(const DestructionMarker&) = delete; |
| DestructionMarker& operator=(const DestructionMarker&) = delete; |
| |
| ~DestructionMarker() override; |
| |
| void OnPrefetchStop(NoStatePrefetchContents* contents) override; |
| |
| private: |
| raw_ptr<DestructionWaiter> waiter_; |
| }; |
| |
| // To be called by a DestructionMarker. |
| void MarkDestruction(FinalStatus reason); |
| |
| base::RunLoop wait_loop_; |
| FinalStatus expected_final_status_; |
| bool saw_correct_status_; |
| std::unique_ptr<DestructionMarker> marker_; |
| }; |
| |
| // Wait until a NoStatePrefetchManager has seen a first contentful paint. |
| class FirstContentfulPaintManagerWaiter |
| : public NoStatePrefetchManagerObserver { |
| public: |
| // Create and return a pointer to a |FirstContentfulPaintManagerWaiter|. The |
| // instance is owned by the |NoStatePrefetchManager|. |
| static FirstContentfulPaintManagerWaiter* Create( |
| NoStatePrefetchManager* manager); |
| |
| FirstContentfulPaintManagerWaiter(const FirstContentfulPaintManagerWaiter&) = |
| delete; |
| FirstContentfulPaintManagerWaiter& operator=( |
| const FirstContentfulPaintManagerWaiter&) = delete; |
| |
| ~FirstContentfulPaintManagerWaiter() override; |
| |
| void OnFirstContentfulPaint() override; |
| |
| // Wait for a first contentful paint to be seen by our NoStatePrefetchManager. |
| void Wait(); |
| |
| private: |
| FirstContentfulPaintManagerWaiter(); |
| |
| std::unique_ptr<base::RunLoop> waiter_; |
| bool saw_fcp_; |
| }; |
| |
| // NoStatePrefetchContentsFactory that uses TestNoStatePrefetchContents. |
| class TestNoStatePrefetchContentsFactory |
| : public NoStatePrefetchContents::Factory { |
| public: |
| TestNoStatePrefetchContentsFactory(); |
| |
| TestNoStatePrefetchContentsFactory( |
| const TestNoStatePrefetchContentsFactory&) = delete; |
| TestNoStatePrefetchContentsFactory& operator=( |
| const TestNoStatePrefetchContentsFactory&) = delete; |
| |
| ~TestNoStatePrefetchContentsFactory() override; |
| |
| std::unique_ptr<TestPrerender> ExpectNoStatePrefetchContents( |
| FinalStatus final_status); |
| |
| void IgnoreNoStatePrefetchContents(); |
| |
| NoStatePrefetchContents* CreateNoStatePrefetchContents( |
| std::unique_ptr<NoStatePrefetchContentsDelegate> delegate, |
| NoStatePrefetchManager* no_state_prefetch_manager, |
| content::BrowserContext* browser_context, |
| const GURL& url, |
| const content::Referrer& referrer, |
| const absl::optional<url::Origin>& initiator_origin, |
| Origin origin) override; |
| |
| private: |
| struct ExpectedContents { |
| ExpectedContents(); |
| ExpectedContents(const ExpectedContents& other); |
| ExpectedContents(FinalStatus final_status, |
| const base::WeakPtr<TestPrerender>& handle); |
| explicit ExpectedContents(bool ignore); |
| ~ExpectedContents(); |
| |
| FinalStatus final_status = FINAL_STATUS_UNKNOWN; |
| bool ignore = false; |
| base::WeakPtr<TestPrerender> handle = nullptr; |
| }; |
| |
| base::circular_deque<ExpectedContents> expected_contents_queue_; |
| }; |
| |
| class PrerenderInProcessBrowserTest : virtual public InProcessBrowserTest { |
| public: |
| PrerenderInProcessBrowserTest(); |
| |
| PrerenderInProcessBrowserTest(const PrerenderInProcessBrowserTest&) = delete; |
| PrerenderInProcessBrowserTest& operator=( |
| const PrerenderInProcessBrowserTest&) = delete; |
| |
| ~PrerenderInProcessBrowserTest() override; |
| |
| void CreatedBrowserMainParts( |
| content::BrowserMainParts* browser_main_parts) override; |
| void TearDownInProcessBrowserTestFixture() override; |
| void SetUpOnMainThread() override; |
| content::SessionStorageNamespace* GetSessionStorageNamespace() const; |
| |
| // Many of the file and server manipulation commands are fussy about paths |
| // being relative or absolute. This makes path absolute if it is not |
| // already. The path must not be empty. |
| std::string MakeAbsolute(const std::string& path); |
| |
| bool UrlIsInNoStatePrefetchManager(const std::string& html_file) const; |
| bool UrlIsInNoStatePrefetchManager(const GURL& url) const; |
| |
| // Convenience function to get the currently active WebContents in |
| // current_browser(). |
| content::WebContents* GetActiveWebContents() const; |
| |
| NoStatePrefetchManager* GetNoStatePrefetchManager() const; |
| |
| TestNoStatePrefetchContents* GetNoStatePrefetchContentsFor( |
| const GURL& url) const; |
| |
| // Set up an HTTPS server. |
| void UseHttpsSrcServer(); |
| |
| // Returns the currently active server. See |UseHttpsSrcServer|. |
| net::EmbeddedTestServer* src_server(); |
| |
| safe_browsing::TestSafeBrowsingServiceFactory* safe_browsing_factory() const { |
| return safe_browsing_factory_.get(); |
| } |
| |
| safe_browsing::FakeSafeBrowsingDatabaseManager* |
| GetFakeSafeBrowsingDatabaseManager(); |
| |
| TestNoStatePrefetchContentsFactory* no_state_prefetch_contents_factory() |
| const { |
| return no_state_prefetch_contents_factory_; |
| } |
| |
| void set_autostart_test_server(bool value) { autostart_test_server_ = value; } |
| |
| void set_browser(Browser* browser) { explicitly_set_browser_ = browser; } |
| |
| Browser* current_browser() const { |
| return explicitly_set_browser_ ? explicitly_set_browser_.get() : browser(); |
| } |
| |
| const base::HistogramTester& histogram_tester() { return histogram_tester_; } |
| |
| // Returns a string for pattern-matching TaskManager tab entries. |
| std::u16string MatchTaskManagerTab(const char* page_title); |
| |
| // Returns a string for pattern-matching TaskManager prerender entries. |
| std::u16string MatchTaskManagerPrerender(const char* page_title); |
| |
| // Returns a GURL for an EmbeddedTestServer that will serves the file |
| // |url_file| with |replacement_text| replacing |replacement_variable|. |
| GURL GetURLWithReplacement(const std::string& url_file, |
| const std::string& replacement_variable, |
| const std::string& replacement_text); |
| |
| protected: |
| // For each FinalStatus in |expected_final_status_queue| creates a prerender |
| // that is going to verify the correctness of its FinalStatus upon |
| // destruction. Waits for creation of the first NoStatePrefetchContents. |
| std::vector<std::unique_ptr<TestPrerender>> NavigateWithPrerenders( |
| const GURL& loader_url, |
| const std::vector<FinalStatus>& expected_final_status_queue); |
| |
| // Creates the URL that instructs the test server to substitute the text |
| // |replacement_variable| in the contents of the file pointed to by |
| // |loader_path| with |url_to_prerender|. Also appends the |loader_query| to |
| // the URL. |
| GURL ServeLoaderURL(const std::string& loader_path, |
| const std::string& replacement_variable, |
| const GURL& url_to_prerender, |
| const std::string& loader_query, |
| const std::string& hostname_alternative = std::string()); |
| |
| // A variation of the above that allows for overriding the hostname. |
| GURL ServeLoaderURLWithHostname(const std::string& loader_path, |
| const std::string& replacement_variable, |
| const GURL& url_to_prerender, |
| const std::string& loader_query, |
| const std::string& hostname); |
| |
| uint32_t GetRequestCount(const GURL& url); |
| void WaitForRequestCount(const GURL& url, uint32_t expected_count); |
| |
| private: |
| void MonitorResourceRequest(const net::test_server::HttpRequest& request); |
| std::unique_ptr<ExternalProtocolHandler::Delegate> |
| external_protocol_handler_delegate_; |
| std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> |
| safe_browsing_factory_; |
| raw_ptr<TestNoStatePrefetchContentsFactory> |
| no_state_prefetch_contents_factory_; |
| raw_ptr<Browser> explicitly_set_browser_; |
| bool autostart_test_server_; |
| base::HistogramTester histogram_tester_; |
| std::unique_ptr<net::EmbeddedTestServer> https_src_server_; |
| |
| // The following are guarded by |lock_| as they're used on multiple threads. |
| std::map<GURL, uint32_t> requests_; |
| GURL waiting_url_; |
| uint32_t waiting_count_ = 0; |
| base::OnceClosure waiting_closure_; |
| base::Lock lock_; |
| }; |
| |
| } // namespace test_utils |
| |
| } // namespace prerender |
| |
| #endif // CHROME_BROWSER_PREFETCH_NO_STATE_PREFETCH_PRERENDER_TEST_UTILS_H_ |