123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- // Copyright 2017 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 <memory>
- #include "base/files/scoped_temp_dir.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/scoped_feature_list.h"
- #include "components/ukm/content/source_url_recorder.h"
- #include "components/ukm/test_ukm_recorder.h"
- #include "content/public/browser/web_contents.h"
- #include "content/public/test/browser_test.h"
- #include "content/public/test/content_browser_test.h"
- #include "content/public/test/content_browser_test_utils.h"
- #include "content/public/test/navigation_handle_observer.h"
- #include "content/public/test/prerender_test_util.h"
- #include "content/shell/browser/shell.h"
- #include "content/shell/browser/shell_browser_context.h"
- #include "content/shell/browser/shell_download_manager_delegate.h"
- #include "services/metrics/public/cpp/ukm_builders.h"
- #include "services/metrics/public/cpp/ukm_source.h"
- #include "third_party/blink/public/common/features.h"
- class SourceUrlRecorderWebContentsObserverBrowserTest
- : public content::ContentBrowserTest {
- public:
- SourceUrlRecorderWebContentsObserverBrowserTest(
- const SourceUrlRecorderWebContentsObserverBrowserTest&) = delete;
- SourceUrlRecorderWebContentsObserverBrowserTest& operator=(
- const SourceUrlRecorderWebContentsObserverBrowserTest&) = delete;
- protected:
- SourceUrlRecorderWebContentsObserverBrowserTest() {
- scoped_feature_list_.InitWithFeatures(
- {ukm::kUkmFeature, blink::features::kPortals}, {});
- }
- ~SourceUrlRecorderWebContentsObserverBrowserTest() override {}
- void SetUpOnMainThread() override {
- content::ContentBrowserTest::SetUpOnMainThread();
- ASSERT_TRUE(embedded_test_server()->Start());
- test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
- ukm::InitializeSourceUrlRecorderForWebContents(shell()->web_contents());
- }
- const ukm::UkmSource* GetSourceForSourceId(const ukm::SourceId source_id) {
- return test_ukm_recorder_->GetSourceForSourceId(source_id);
- }
- const ukm::UkmSource* GetSourceForNavigationId(int64_t navigation_id) {
- CHECK_GT(navigation_id, 0);
- return GetSourceForSourceId(ukm::ConvertToSourceId(
- navigation_id, ukm::SourceIdType::NAVIGATION_ID));
- }
- GURL GetAssociatedURLForWebContentsDocument() {
- const ukm::UkmSource* src = test_ukm_recorder_->GetSourceForSourceId(
- shell()->web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId());
- return src ? src->url() : GURL();
- }
- const ukm::TestAutoSetUkmRecorder& test_ukm_recorder() const {
- return *test_ukm_recorder_;
- }
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
- std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
- };
- class SourceUrlRecorderWebContentsObserverDownloadBrowserTest
- : public SourceUrlRecorderWebContentsObserverBrowserTest {
- protected:
- void SetUpOnMainThread() override {
- SourceUrlRecorderWebContentsObserverBrowserTest::SetUpOnMainThread();
- // Set up a test download directory, in order to prevent prompting for
- // handling downloads.
- ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
- content::ShellDownloadManagerDelegate* delegate =
- static_cast<content::ShellDownloadManagerDelegate*>(
- shell()
- ->web_contents()
- ->GetBrowserContext()
- ->GetDownloadManagerDelegate());
- delegate->SetDownloadBehaviorForTesting(downloads_directory_.GetPath());
- }
- private:
- base::ScopedTempDir downloads_directory_;
- };
- IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest, Basic) {
- using Entry = ukm::builders::DocumentCreated;
- GURL url = embedded_test_server()->GetURL("/title1.html");
- content::NavigationHandleObserver observer(shell()->web_contents(), url);
- EXPECT_TRUE(content::NavigateToURL(shell(), url));
- EXPECT_TRUE(observer.has_committed());
- const ukm::UkmSource* source =
- GetSourceForNavigationId(observer.navigation_id());
- EXPECT_NE(nullptr, source);
- EXPECT_EQ(url, source->url());
- EXPECT_EQ(1u, source->urls().size());
- EXPECT_EQ(url, GetAssociatedURLForWebContentsDocument());
- // Check we have created a DocumentCreated event.
- auto ukm_entries = test_ukm_recorder().GetEntriesByName(Entry::kEntryName);
- EXPECT_EQ(1u, ukm_entries.size());
- EXPECT_EQ(source->id(), *test_ukm_recorder().GetEntryMetric(
- ukm_entries[0], Entry::kNavigationSourceIdName));
- EXPECT_EQ(1, *test_ukm_recorder().GetEntryMetric(ukm_entries[0],
- Entry::kIsMainFrameName));
- EXPECT_NE(source->id(), ukm_entries[0]->source_id);
- }
- // Test correctness of sources and DocumentCreated entries when a navigation
- // leads to creation of main frame and embedded subframe documents.
- IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest,
- IgnoreUrlInSubframe) {
- using Entry = ukm::builders::DocumentCreated;
- GURL main_url = embedded_test_server()->GetURL("/page_with_iframe.html");
- GURL subframe_url = embedded_test_server()->GetURL("/title1.html");
- content::NavigationHandleObserver main_observer(shell()->web_contents(),
- main_url);
- content::NavigationHandleObserver subframe_observer(shell()->web_contents(),
- subframe_url);
- EXPECT_TRUE(content::NavigateToURL(shell(), main_url));
- EXPECT_TRUE(main_observer.has_committed());
- EXPECT_TRUE(main_observer.is_main_frame());
- EXPECT_TRUE(subframe_observer.has_committed());
- EXPECT_FALSE(subframe_observer.is_main_frame());
- const ukm::UkmSource* navigation_source =
- GetSourceForNavigationId(main_observer.navigation_id());
- EXPECT_NE(nullptr, navigation_source);
- EXPECT_EQ(main_url, navigation_source->url());
- EXPECT_EQ(nullptr,
- GetSourceForNavigationId(subframe_observer.navigation_id()));
- EXPECT_EQ(main_url, GetAssociatedURLForWebContentsDocument());
- // Check we have created one DocumentCreated event for each of the frames.
- auto ukm_entries = test_ukm_recorder().GetEntriesByName(Entry::kEntryName);
- EXPECT_EQ(2u, ukm_entries.size());
- // Both events have the same navigation source id, and have different values
- // for the kIsMainFrameName metric.
- EXPECT_EQ(navigation_source->id(),
- *test_ukm_recorder().GetEntryMetric(
- ukm_entries[0], Entry::kNavigationSourceIdName));
- EXPECT_EQ(navigation_source->id(),
- *test_ukm_recorder().GetEntryMetric(
- ukm_entries[1], Entry::kNavigationSourceIdName));
- EXPECT_NE(*test_ukm_recorder().GetEntryMetric(ukm_entries[0],
- Entry::kIsMainFrameName),
- *test_ukm_recorder().GetEntryMetric(ukm_entries[1],
- Entry::kIsMainFrameName));
- // The two DocumentCreated entries have source ids corresponding to the
- // document source ids, which are different from the id of the navigation
- // source.
- EXPECT_NE(ukm_entries[0]->source_id, ukm_entries[1]->source_id);
- EXPECT_NE(navigation_source->id(), ukm_entries[0]->source_id);
- EXPECT_NE(navigation_source->id(), ukm_entries[1]->source_id);
- }
- IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverDownloadBrowserTest,
- IgnoreDownload) {
- GURL url(embedded_test_server()->GetURL("/download-test1.lib"));
- content::NavigationHandleObserver observer(shell()->web_contents(), url);
- EXPECT_TRUE(content::NavigateToURLAndExpectNoCommit(shell(), url));
- EXPECT_FALSE(observer.has_committed());
- EXPECT_TRUE(observer.is_download());
- EXPECT_EQ(nullptr, GetSourceForNavigationId(observer.navigation_id()));
- EXPECT_EQ(GURL(), GetAssociatedURLForWebContentsDocument());
- }
- IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest,
- Portal) {
- GURL url = embedded_test_server()->GetURL("/title1.html");
- {
- content::NavigationHandleObserver observer(shell()->web_contents(), url);
- EXPECT_TRUE(content::NavigateToURL(shell(), url));
- const ukm::UkmSource* source =
- GetSourceForNavigationId(observer.navigation_id());
- EXPECT_NE(nullptr, source);
- EXPECT_EQ(url, source->url());
- }
- // Create the portal and get its associated WebContents.
- content::WebContentsAddedObserver contents_observer;
- EXPECT_TRUE(
- ExecJs(shell()->web_contents(),
- "document.body.appendChild(document.createElement('portal'));"));
- content::WebContents* portal_contents = contents_observer.GetWebContents();
- EXPECT_TRUE(portal_contents->IsPortal());
- EXPECT_NE(portal_contents, shell()->web_contents());
- // Register the UKM SourceUrlRecorder for the portal WebContents. Normally
- // this would be done automatically via TabHelper registration, but TabHelper
- // registration doesn't run in //content.
- ukm::InitializeSourceUrlRecorderForWebContents(portal_contents);
- // Navigate the portal and wait for the navigation to finish.
- GURL portal_url = embedded_test_server()->GetURL("/title2.html");
- content::TestNavigationManager portal_nav_manager(portal_contents,
- portal_url);
- content::NavigationHandleObserver portal_nav_observer(portal_contents,
- portal_url);
- EXPECT_TRUE(
- ExecJs(shell()->web_contents(),
- base::StringPrintf("document.querySelector('portal').src = '%s';",
- portal_url.spec().c_str())));
- portal_nav_manager.WaitForNavigationFinished();
- EXPECT_TRUE(portal_nav_observer.has_committed());
- EXPECT_FALSE(portal_nav_observer.is_error());
- // Ensure no UKM source was created for the portal navigation.
- // TODO(crbug/1078355): Ensure the source was created but no URL was recorded.
- EXPECT_EQ(nullptr,
- GetSourceForNavigationId(portal_nav_observer.navigation_id()));
- // Activate the portal, which should cause a URL to be recorded for the
- // associated UKM source. Activation is similar to a main frame navigation
- // from the user standpoint, as it causes the portal to shift from being in a
- // more iframe-like state to becoming the main frame in the associated browser
- // tab.
- std::string activated_listener = R"(
- activated = false;
- window.addEventListener('portalactivate', e => {
- activated = true;
- });
- )";
- EXPECT_TRUE(ExecJs(portal_contents, activated_listener));
- EXPECT_TRUE(ExecJs(shell()->web_contents(),
- "document.querySelector('portal').activate()"));
- std::string activated_poll = R"(
- setInterval(() => {
- if (activated)
- window.domAutomationController.send(true);
- }, 10);
- )";
- EXPECT_EQ(true, EvalJs(portal_contents, activated_poll,
- content::EXECUTE_SCRIPT_USE_MANUAL_REPLY));
- // The activated portal contents should be the currently active contents.
- EXPECT_EQ(portal_contents, shell()->web_contents());
- // TODO(crbug/1078143): enable when UKM sources are created for activated
- // portals.
- #if 0
- // Ensure a UKM source was created for the activated portal, and a URL was
- // recorded.
- const ukm::UkmSource* portal_source =
- GetSourceForNavigationId(portal_nav_observer.navigation_id());
- EXPECT_NE(nullptr, portal_source);
- EXPECT_EQ(portal_url, portal_source->url());
- #endif
- {
- // Ensure a UKM source is recorded for navigations in an activated portal.
- content::NavigationHandleObserver observer(portal_contents, url);
- EXPECT_TRUE(content::NavigateToURL(shell(), url));
- EXPECT_NE(nullptr, GetSourceForNavigationId(observer.navigation_id()));
- }
- }
- class SourceUrlRecorderWebContentsObserverPrerenderBrowserTest
- : public SourceUrlRecorderWebContentsObserverBrowserTest {
- public:
- SourceUrlRecorderWebContentsObserverPrerenderBrowserTest()
- : prerender_helper_(base::BindRepeating(
- &SourceUrlRecorderWebContentsObserverPrerenderBrowserTest::
- web_contents,
- base::Unretained(this))) {}
- ~SourceUrlRecorderWebContentsObserverPrerenderBrowserTest() override =
- default;
- content::test::PrerenderTestHelper* prerender_helper() {
- return &prerender_helper_;
- }
- content::WebContents* web_contents() { return shell()->web_contents(); }
- private:
- content::test::PrerenderTestHelper prerender_helper_;
- };
- IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverPrerenderBrowserTest,
- IgnoreUrlInPrerender) {
- GURL url = embedded_test_server()->GetURL("/title1.html");
- content::NavigationHandleObserver observer(web_contents(), url);
- EXPECT_TRUE(content::NavigateToURL(shell(), url));
- EXPECT_TRUE(observer.has_committed());
- const ukm::UkmSource* source1 =
- GetSourceForNavigationId(observer.navigation_id());
- EXPECT_NE(nullptr, source1);
- EXPECT_EQ(1u, source1->urls().size());
- EXPECT_EQ(url, source1->url());
- EXPECT_EQ(url, GetAssociatedURLForWebContentsDocument());
- // Load a page in the prerendering.
- GURL prerender_url =
- embedded_test_server()->GetURL("/title1.html?prerendering");
- content::NavigationHandleObserver prerender_observer(web_contents(),
- prerender_url);
- prerender_helper()->AddPrerender(prerender_url);
- // Ensure no UKM source was created for the prerendering navigation.
- EXPECT_EQ(nullptr,
- GetSourceForNavigationId(prerender_observer.navigation_id()));
- EXPECT_EQ(url, GetAssociatedURLForWebContentsDocument());
- // Navigate the primary page to the URL.
- prerender_helper()->NavigatePrimaryPage(prerender_url);
- const ukm::UkmSource* source2 =
- GetSourceForNavigationId(prerender_observer.navigation_id());
- EXPECT_EQ(1u, source2->urls().size());
- EXPECT_EQ(prerender_url, source2->url());
- GURL expected_ukm_url;
- // TODO(crbug.com/1245014): The URL is not assigned yet for prerendering
- // UKM source ids, so expect it to not be set.
- // expected_ukm_url = prerender_url;
- EXPECT_EQ(expected_ukm_url, GetAssociatedURLForWebContentsDocument());
- EXPECT_NE(source1, source2);
- }
|