Index: chrome/browser/page_load_metrics/page_load_metrics_mojofication_browsertest.cc |
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_mojofication_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_mojofication_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..aef526fea94b17ac0de2f1ca3cf17c9b6c4a64a6 |
--- /dev/null |
+++ b/chrome/browser/page_load_metrics/page_load_metrics_mojofication_browsertest.cc |
@@ -0,0 +1,923 @@ |
+// Copyright 2015 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. |
+ |
+#include "base/files/scoped_temp_dir.h" |
+#include "base/macros.h" |
+#include "base/test/histogram_tester.h" |
+#include "base/test/scoped_feature_list.h" |
+#include "base/time/time.h" |
+#include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h" |
+#include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h" |
+#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h" |
+#include "chrome/browser/page_load_metrics/observers/document_write_page_load_metrics_observer.h" |
+#include "chrome/browser/page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h" |
+#include "chrome/browser/page_load_metrics/page_load_tracker.h" |
+#include "chrome/browser/prerender/prerender_histograms.h" |
+#include "chrome/browser/prerender/prerender_origin.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/browser_navigator_params.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "chrome/common/chrome_features.h" |
+#include "chrome/common/pref_names.h" |
+#include "chrome/common/url_constants.h" |
+#include "chrome/test/base/in_process_browser_test.h" |
+#include "chrome/test/base/ui_test_utils.h" |
+#include "components/prefs/pref_service.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/test/browser_test_utils.h" |
+#include "content/public/test/download_test_observer.h" |
+#include "content/public/test/web_contents_binding_set_test_binder.h" |
+#include "mojo/public/cpp/bindings/associated_binding.h" |
+#include "net/http/failing_http_transaction_factory.h" |
+#include "net/http/http_cache.h" |
+#include "net/test/embedded_test_server/embedded_test_server.h" |
+#include "net/test/url_request/url_request_failed_job.h" |
+#include "net/url_request/url_request_context.h" |
+#include "net/url_request/url_request_context_getter.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+ |
+namespace { |
+ |
+void FailAllNetworkTransactions(net::URLRequestContextGetter* getter) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ net::HttpCache* cache( |
+ getter->GetURLRequestContext()->http_transaction_factory()->GetCache()); |
+ DCHECK(cache); |
+ std::unique_ptr<net::FailingHttpTransactionFactory> factory( |
+ new net::FailingHttpTransactionFactory(cache->GetSession(), |
+ net::ERR_FAILED)); |
+ // Throw away old version; since this is a browser test, there is no |
+ // need to restore the old state. |
+ cache->SetHttpNetworkTransactionFactoryForTesting(std::move(factory)); |
+} |
+ |
+// Wait until we dispatch PageLoadTiming through UpdateTiming. |
+// matching a PageLoadTiming. See WaitForTimingUpdated for details. |
+class PageLoadTimingObserver { |
+ public: |
+ // A bitvector to express which timing fields to match on. |
+ enum ExpectedTimingFields { |
+ FIRST_PAINT = 1 << 0, |
+ FIRST_CONTENTFUL_PAINT = 1 << 1, |
+ STYLE_UPDATE_BEFORE_FCP = 1 << 2 |
+ }; |
+ |
+ PageLoadTimingObserver() { |
+ // Roundtrip to the IO thread, to ensure that the filter is properly |
+ // installed. |
+ content::BrowserThread::PostTaskAndReply( |
+ content::BrowserThread::IO, FROM_HERE, base::Bind(&base::DoNothing), |
+ base::Bind(&PageLoadTimingObserver::Quit, base::Unretained(this))); |
+ run_loop_.reset(new base::RunLoop()); |
+ run_loop_->Run(); |
+ run_loop_.reset(nullptr); |
+ } |
+ |
+ ~PageLoadTimingObserver() {} |
+ |
+ // Add the given timing fields to the set of fields to match on. |
+ void AddMatchingFields(ExpectedTimingFields fields) { |
+ matching_fields_ |= fields; |
+ } |
+ |
+ // Instructs observer to also watch for |count| |
+ // WebLoadingBehaviorDocumentWriteBlockReload events. |
+ void MatchDocumentWriteBlockReload(int count) { |
+ match_document_write_block_reload_ = count; |
+ } |
+ |
+ // Waits for a PageLoadTiming that matches the fields set by |
+ // Waits for a TimingUpdated IPC that matches the fields set by |
+ // UpdateTiming to end this wait. |
+ void WaitForTimingUpdated() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ if (matched_timing_update_) |
+ return; |
+ |
+ run_loop_.reset(new base::RunLoop()); |
+ run_loop_->Run(); |
+ run_loop_.reset(nullptr); |
+ } |
+ |
+ void UpdateTiming(const page_load_metrics::PageLoadTiming& timing, |
+ const page_load_metrics::PageLoadMetadata& metadata) { |
+ if (match_document_write_block_reload_ > 0 && |
+ metadata.behavior_flags & |
+ blink::WebLoadingBehaviorFlag:: |
+ kWebLoadingBehaviorDocumentWriteBlockReload) { |
+ --match_document_write_block_reload_; |
+ } |
+ |
+ if (match_document_write_block_reload_ > 0) { |
+ return; |
+ } |
+ |
+ if ((!(matching_fields_ & FIRST_PAINT) || |
+ timing.paint_timing.first_paint) && |
+ (!(matching_fields_ & FIRST_CONTENTFUL_PAINT) || |
+ timing.paint_timing.first_contentful_paint) && |
+ (!(matching_fields_ & STYLE_UPDATE_BEFORE_FCP) || |
+ timing.style_sheet_timing.update_style_duration_before_fcp)) { |
+ // Ensure that any other handlers of this message, for example the real |
+ // PageLoadMetric observers, get a chance to handle this message before |
+ // this waiter unblocks. |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&PageLoadTimingObserver::BounceTimingUpdate, |
+ base::Unretained(this))); |
+ } |
+ } |
+ |
+ private: |
+ void BounceTimingUpdate() { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&PageLoadTimingObserver::SetTimingUpdatedAndQuit, |
+ base::Unretained(this))); |
+ } |
+ |
+ void Quit() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ if (run_loop_) |
+ run_loop_->Quit(); |
+ } |
+ |
+ void SetTimingUpdatedAndQuit() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ matched_timing_update_ = true; |
+ Quit(); |
+ } |
+ |
+ std::unique_ptr<base::RunLoop> run_loop_; |
+ int matching_fields_ = 0; // A bitvector composed from ExpectedTimingFields. |
+ bool matched_timing_update_ = false; |
+ int match_document_write_block_reload_ = 0; |
+}; |
+ |
+} // namespace |
+ |
+namespace page_load_metrics { |
+ |
+class FakePageLoadMetrics : public mojom::PageLoadMetrics { |
+ public: |
+ explicit FakePageLoadMetrics(content::RenderFrameHost* render_frame_host) { |
+ metrics_observer_ = content::WebContentsUserData< |
+ page_load_metrics::MetricsWebContentsObserver>:: |
+ FromWebContents( |
+ content::WebContents::FromRenderFrameHost(render_frame_host)); |
+ metrics_observer_->page_load_metrics_binding_for_testing() |
+ .SetCurrentTargetFrameForTesting(render_frame_host); |
+ } |
+ |
+ ~FakePageLoadMetrics() override {} |
+ |
+ void AddObserver(PageLoadTimingObserver* observer) { |
+ observers_.push_back(base::WrapUnique(observer)); |
+ } |
+ |
+ private: |
+ void UpdateTiming(const PageLoadTiming& timing, |
+ const PageLoadMetadata& metadata) override { |
+ metrics_observer_->UpdateTiming(timing, metadata); |
+ for (auto& observer : observers_) { |
+ observer->UpdateTiming(timing, metadata); |
+ } |
+ } |
+ |
+ MetricsWebContentsObserver* metrics_observer_; |
+ std::vector<std::unique_ptr<PageLoadTimingObserver>> observers_; |
+}; |
+ |
+} // namespace page_load_metrics |
+ |
+namespace { |
+ |
+class FakePageLoadMetricsBinder |
+ : public content::WebContentsBindingSetTestBinder< |
+ page_load_metrics::mojom::PageLoadMetrics> { |
+ public: |
+ FakePageLoadMetricsBinder( |
+ page_load_metrics::mojom::PageLoadMetrics* page_load_metrics) |
+ : page_load_metrics_(page_load_metrics) {} |
+ ~FakePageLoadMetricsBinder() override {} |
+ |
+ void BindRequest(content::RenderFrameHost* frame_host, |
+ page_load_metrics::mojom::PageLoadMetricsAssociatedRequest |
+ request) override { |
+ bindings_.AddBinding(page_load_metrics_, std::move(request), frame_host); |
+ } |
+ |
+ private: |
+ page_load_metrics::mojom::PageLoadMetrics* page_load_metrics_; |
+ mojo::AssociatedBindingSet<page_load_metrics::mojom::PageLoadMetrics, |
+ content::RenderFrameHost*> |
+ bindings_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FakePageLoadMetricsBinder); |
+}; |
+ |
+} // namespace |
+ |
+class PageLoadMetricsMojoficationBrowserTest : public InProcessBrowserTest { |
+ public: |
+ PageLoadMetricsMojoficationBrowserTest() {} |
+ ~PageLoadMetricsMojoficationBrowserTest() override {} |
+ |
+ void SetUpCommandLine(base::CommandLine* command_line) override { |
+ // We need to set the feature state before the render process is created, |
+ // in order for it to inherit the feature state from the browser process. |
+ // SetUp() runs too early, and SetUpOnMainThread() runs too late. |
+ scoped_feature_list_.InitAndEnableFeature( |
+ features::kPageLoadMetricsMojofication); |
+ } |
+ |
+ protected: |
+ void NavigateToUntrackedUrl() { |
+ ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); |
+ } |
+ |
+ bool NoPageLoadMetricsRecorded() { |
+ // Determine whether any 'public' page load metrics are recorded. We exclude |
+ // 'internal' metrics as these may be recorded for debugging purposes. |
+ size_t total_pageload_histograms = |
+ histogram_tester_.GetTotalCountsForPrefix("PageLoad.").size(); |
+ size_t total_internal_histograms = |
+ histogram_tester_.GetTotalCountsForPrefix("PageLoad.Internal.").size(); |
+ DCHECK_GE(total_pageload_histograms, total_internal_histograms); |
+ return total_pageload_histograms - total_internal_histograms == 0; |
+ } |
+ |
+ PageLoadTimingObserver* CreatePageLoadTimingObserver() { |
+ if (!fake_page_load_metrics_) { |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ fake_page_load_metrics_.reset(new page_load_metrics::FakePageLoadMetrics( |
+ web_contents->GetMainFrame())); |
+ content::WebContentsBindingSet::GetForWebContents< |
+ page_load_metrics::mojom::PageLoadMetrics>(web_contents) |
+ ->SetBinderForTesting(base::MakeUnique<FakePageLoadMetricsBinder>( |
+ fake_page_load_metrics_.get())); |
+ } |
+ PageLoadTimingObserver* observer = new PageLoadTimingObserver(); |
+ fake_page_load_metrics_->AddObserver(observer); |
+ return observer; |
+ } |
+ |
+ base::test::ScopedFeatureList scoped_feature_list_; |
+ std::unique_ptr<page_load_metrics::FakePageLoadMetrics> |
+ fake_page_load_metrics_; |
+ base::HistogramTester histogram_tester_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(PageLoadMetricsMojoficationBrowserTest); |
+}; |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, NoNavigation) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, NewPage) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramParseDuration, 1); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramParseBlockedOnScriptLoad, 1); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramParseBlockedOnScriptExecution, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramTotalBytes, 1); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramPageTimingForegroundDuration, 1); |
+ |
+ // Verify that NoPageLoadMetricsRecorded returns false when PageLoad metrics |
+ // have been recorded. |
+ EXPECT_FALSE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ SameDocumentNavigation) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL("/title1.html#hash")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ SameUrlNavigation) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ // We expect one histogram sample for each navigation to title1.html. |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 2); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 2); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 2); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NonHtmlMainResource) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/circle.svg")); |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NonHttpOrHttpsUrl) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL)); |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, HttpErrorPage) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL("/page_load_metrics/404.html")); |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ ChromeErrorPage) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ // Configure the network stack to fail all attempted loads with a network |
+ // error, which will cause Chrome to display an error page. |
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = |
+ browser()->profile()->GetRequestContext(); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&FailAllNetworkTransactions, |
+ base::RetainedRef(url_request_context_getter))); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, Ignore204Pages) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/page204.html")); |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ IgnoreDownloads) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ base::ScopedTempDir downloads_directory; |
+ ASSERT_TRUE(downloads_directory.CreateUniqueTempDir()); |
+ browser()->profile()->GetPrefs()->SetFilePath( |
+ prefs::kDownloadDefaultDirectory, downloads_directory.GetPath()); |
+ content::DownloadTestObserverTerminal downloads_observer( |
+ content::BrowserContext::GetDownloadManager(browser()->profile()), |
+ 1, // == wait_count (only waiting for "download-test3.gif"). |
+ content::DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL("/download-test3.gif")); |
+ downloads_observer.WaitForFinished(); |
+ |
+ NavigateToUntrackedUrl(); |
+ EXPECT_TRUE(NoPageLoadMetricsRecorded()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ PreloadDocumentWrite) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_external_script.html")); |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteParseStartToFirstContentfulPaint, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoPreloadDocumentWrite) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_no_script.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteParseStartToFirstContentfulPaint, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoDocumentWrite) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteParseStartToFirstContentfulPaint, 0); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 0); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ DocumentWriteBlock) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_script_block.html")); |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ DocumentWriteReload) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ PageLoadTimingObserver* reload_observer = CreatePageLoadTimingObserver(); |
+ reload_observer->MatchDocumentWriteBlockReload(2); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_script_block.html")); |
+ |
+ // Reload should not log the histogram as the script is not blocked. |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_script_block.html")); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_script_block.html")); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 1); |
+ |
+ fcp_observer->WaitForTimingUpdated(); |
+ reload_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 1); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockReloadCount, 2); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ DocumentWriteAsync) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_script_async.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 0); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ DocumentWriteSameDomain) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_external_script.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 0); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoDocumentWriteScript) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/document_write_no_script.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramDocWriteBlockParseStartToFirstContentfulPaint, 0); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDocWriteBlockCount, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, BadXhtml) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* timing_observer = CreatePageLoadTimingObserver(); |
+ timing_observer->AddMatchingFields(PageLoadTimingObserver::FIRST_PAINT); |
+ |
+ // When an XHTML page contains invalid XML, it causes a paint of the error |
+ // message without a layout. Page load metrics currently treats this as an |
+ // error. Eventually, we'll fix this by special casing the handling of |
+ // documents with non-well-formed XML on the blink side. See crbug.com/627607 |
+ // for more. |
+ ui_test_utils::NavigateToURL( |
+ browser(), |
+ embedded_test_server()->GetURL("/page_load_metrics/badxml.xhtml")); |
+ |
+ timing_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 0); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstPaint, 0); |
+ histogram_tester_.ExpectTotalCount(page_load_metrics::internal::kErrorEvents, |
+ 1); |
+ histogram_tester_.ExpectBucketCount( |
+ page_load_metrics::internal::kErrorEvents, |
+ page_load_metrics::ERR_BAD_TIMING_IPC_INVALID_TIMING, 1); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ page_load_metrics::internal::kPageLoadTimingStatus, 1); |
+ histogram_tester_.ExpectBucketCount( |
+ page_load_metrics::internal::kPageLoadTimingStatus, |
+ page_load_metrics::internal::INVALID_ORDER_FIRST_LAYOUT_FIRST_PAINT, 1); |
+} |
+ |
+// Test code that aborts provisional navigations. |
+// TODO(csharrison): Move these to unit tests once the navigation API in content |
+// properly calls NavigationHandle/NavigationThrottle methods. |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ AbortNewNavigation) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ GURL url(embedded_test_server()->GetURL("/title1.html")); |
+ chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); |
+ content::TestNavigationManager manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url); |
+ |
+ chrome::Navigate(¶ms); |
+ EXPECT_TRUE(manager.WaitForRequestStart()); |
+ |
+ GURL url2(embedded_test_server()->GetURL("/title2.html")); |
+ chrome::NavigateParams params2(browser(), url2, |
+ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); |
+ content::TestNavigationManager manager2( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url2); |
+ chrome::Navigate(¶ms2); |
+ |
+ manager2.WaitForNavigationFinished(); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramAbortNewNavigationBeforeCommit, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, AbortReload) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ GURL url(embedded_test_server()->GetURL("/title1.html")); |
+ chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); |
+ content::TestNavigationManager manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url); |
+ |
+ chrome::Navigate(¶ms); |
+ EXPECT_TRUE(manager.WaitForRequestStart()); |
+ |
+ chrome::NavigateParams params2(browser(), url, ui::PAGE_TRANSITION_RELOAD); |
+ content::TestNavigationManager manager2( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url); |
+ chrome::Navigate(¶ms2); |
+ |
+ manager2.WaitForNavigationFinished(); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramAbortReloadBeforeCommit, 1); |
+} |
+ |
+// TODO(crbug.com/675061): Flaky on Win7 dbg. |
+#if defined(OS_WIN) |
+#define MAYBE_AbortClose DISABLED_AbortClose |
+#else |
+#define MAYBE_AbortClose AbortClose |
+#endif |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ MAYBE_AbortClose) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ GURL url(embedded_test_server()->GetURL("/title1.html")); |
+ chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); |
+ content::TestNavigationManager manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url); |
+ |
+ chrome::Navigate(¶ms); |
+ EXPECT_TRUE(manager.WaitForRequestStart()); |
+ |
+ browser()->tab_strip_model()->GetActiveWebContents()->Close(); |
+ |
+ manager.WaitForNavigationFinished(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramAbortCloseBeforeCommit, |
+ 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, AbortMultiple) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ GURL url(embedded_test_server()->GetURL("/title1.html")); |
+ chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); |
+ content::TestNavigationManager manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url); |
+ |
+ chrome::Navigate(¶ms); |
+ EXPECT_TRUE(manager.WaitForRequestStart()); |
+ |
+ GURL url2(embedded_test_server()->GetURL("/title2.html")); |
+ chrome::NavigateParams params2(browser(), url2, ui::PAGE_TRANSITION_TYPED); |
+ content::TestNavigationManager manager2( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url2); |
+ chrome::Navigate(¶ms2); |
+ |
+ EXPECT_TRUE(manager2.WaitForRequestStart()); |
+ manager.WaitForNavigationFinished(); |
+ |
+ GURL url3(embedded_test_server()->GetURL("/title3.html")); |
+ chrome::NavigateParams params3(browser(), url3, ui::PAGE_TRANSITION_TYPED); |
+ content::TestNavigationManager manager3( |
+ browser()->tab_strip_model()->GetActiveWebContents(), url3); |
+ chrome::Navigate(¶ms3); |
+ |
+ EXPECT_TRUE(manager3.WaitForRequestStart()); |
+ manager2.WaitForNavigationFinished(); |
+ |
+ manager3.WaitForNavigationFinished(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramAbortNewNavigationBeforeCommit, 2); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoAbortMetricsOnClientRedirect) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ GURL first_url(embedded_test_server()->GetURL("/title1.html")); |
+ ui_test_utils::NavigateToURL(browser(), first_url); |
+ |
+ GURL second_url(embedded_test_server()->GetURL("/title2.html")); |
+ chrome::NavigateParams params(browser(), second_url, |
+ ui::PAGE_TRANSITION_LINK); |
+ content::TestNavigationManager manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), second_url); |
+ chrome::Navigate(¶ms); |
+ EXPECT_TRUE(manager.WaitForRequestStart()); |
+ |
+ { |
+ content::TestNavigationManager reload_manager( |
+ browser()->tab_strip_model()->GetActiveWebContents(), first_url); |
+ EXPECT_TRUE(content::ExecuteScript( |
+ browser()->tab_strip_model()->GetActiveWebContents(), |
+ "window.location.reload();")); |
+ } |
+ |
+ manager.WaitForNavigationFinished(); |
+ |
+ EXPECT_TRUE(histogram_tester_ |
+ .GetTotalCountsForPrefix("PageLoad.Experimental.AbortTiming.") |
+ .empty()); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ FirstMeaningfulPaintRecorded) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ |
+ // Wait until the renderer finishes observing layouts. |
+ const int kNetworkIdleTime = 3000; |
+ const int kMargin = 500; |
+ const std::string javascript = base::StringPrintf( |
+ "setTimeout(() => window.domAutomationController.send(true), %d)", |
+ kNetworkIdleTime + kMargin); |
+ bool result; |
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool( |
+ browser()->tab_strip_model()->GetActiveWebContents(), javascript, |
+ &result)); |
+ EXPECT_TRUE(result); |
+ |
+ NavigateToUntrackedUrl(); |
+ histogram_tester_.ExpectUniqueSample( |
+ internal::kHistogramFirstMeaningfulPaintStatus, |
+ internal::FIRST_MEANINGFUL_PAINT_RECORDED, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstMeaningfulPaint, |
+ 1); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramParseStartToFirstMeaningfulPaint, 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ FirstMeaningfulPaintNotRecorded) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/page_with_active_connections.html")); |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ // Navigate away before a FMP is reported. |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectUniqueSample( |
+ internal::kHistogramFirstMeaningfulPaintStatus, |
+ internal::FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_NETWORK_STABLE, 1); |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstMeaningfulPaint, |
+ 0); |
+ histogram_tester_.ExpectTotalCount( |
+ internal::kHistogramParseStartToFirstMeaningfulPaint, 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoStatePrefetchObserverCacheable) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/title1.html")); |
+ |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ "Prerender.none_PrefetchTTFCP.Reference.NoStore.Visible", 0); |
+ histogram_tester_.ExpectTotalCount( |
+ "Prerender.none_PrefetchTTFCP.Reference.Cacheable.Visible", 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, |
+ NoStatePrefetchObserverNoStore) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::FIRST_CONTENTFUL_PAINT); |
+ |
+ ui_test_utils::NavigateToURL(browser(), |
+ embedded_test_server()->GetURL("/nostore.html")); |
+ |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount( |
+ "Prerender.none_PrefetchTTFCP.Reference.NoStore.Visible", 1); |
+ histogram_tester_.ExpectTotalCount( |
+ "Prerender.none_PrefetchTTFCP.Reference.Cacheable.Visible", 0); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, CSSTiming) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ PageLoadTimingObserver* fcp_observer = CreatePageLoadTimingObserver(); |
+ fcp_observer->AddMatchingFields( |
+ PageLoadTimingObserver::STYLE_UPDATE_BEFORE_FCP); |
+ |
+ // Careful: Blink code clamps timestamps to 5us, so any CSS parsing we do here |
+ // must take >> 5us, otherwise we'll log 0 for the value and it will remain |
+ // unset here. |
+ ui_test_utils::NavigateToURL( |
+ browser(), |
+ embedded_test_server()->GetURL("/page_load_metrics/page_with_css.html")); |
+ NavigateToUntrackedUrl(); |
+ fcp_observer->WaitForTimingUpdated(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstContentfulPaint, |
+ 1); |
+ histogram_tester_.ExpectTotalCount( |
+ "PageLoad.CSSTiming.Parse.BeforeFirstContentfulPaint", 1); |
+ histogram_tester_.ExpectTotalCount( |
+ "PageLoad.CSSTiming.Update.BeforeFirstContentfulPaint", 1); |
+ histogram_tester_.ExpectTotalCount( |
+ "PageLoad.CSSTiming.ParseAndUpdate.BeforeFirstContentfulPaint", 1); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsMojoficationBrowserTest, PayloadSize) { |
+ ASSERT_TRUE( |
+ base::FeatureList::IsEnabled(features::kPageLoadMetricsMojofication)); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL( |
+ "/page_load_metrics/large.html")); |
+ NavigateToUntrackedUrl(); |
+ |
+ histogram_tester_.ExpectTotalCount(internal::kHistogramTotalBytes, 1); |
+ |
+ // Verify that there is a single sample recorded in the 10kB bucket (the size |
+ // of the main HTML response). |
+ histogram_tester_.ExpectBucketCount(internal::kHistogramTotalBytes, 10, 1); |
+} |