1 // Copyright 2018 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 #include "base/task/post_task.h"
6 #include "build/build_config.h"
7 #include "chrome/browser/ui/browser.h"
8 #include "chrome/test/base/in_process_browser_test.h"
9 #include "components/ukm/test_ukm_recorder.h"
10 #include "content/public/browser/navigation_controller.h"
11 #include "content/public/test/browser_test.h"
12 #include "content/public/test/browser_test_utils.h"
13 #include "content/public/test/test_frame_navigation_observer.h"
14 #include "net/dns/mock_host_resolver.h"
15 #include "services/metrics/public/cpp/ukm_builders.h"
16 #include "services/metrics/public/cpp/ukm_source.h"
17 
18 namespace chrome {
19 
20 namespace {
21 
22 class AutoplayMetricsBrowserTest : public InProcessBrowserTest {
23  public:
24   using Entry = ukm::builders::Media_Autoplay_Attempt;
25   using CreatedEntry = ukm::builders::DocumentCreated;
26 
SetUpOnMainThread()27   void SetUpOnMainThread() override {
28     host_resolver()->AddRule("*", "127.0.0.1");
29     content::SetupCrossSiteRedirector(embedded_test_server());
30     ASSERT_TRUE(embedded_test_server()->Start());
31   }
32 
TryAutoplay(ukm::TestUkmRecorder & ukm_recorder,const content::ToRenderFrameHost & adapter)33   void TryAutoplay(ukm::TestUkmRecorder& ukm_recorder,
34                    const content::ToRenderFrameHost& adapter) {
35     base::RunLoop run_loop;
36     ukm_recorder.SetOnAddEntryCallback(Entry::kEntryName,
37                                        run_loop.QuitClosure());
38     EXPECT_TRUE(ExecuteScriptWithoutUserGesture(adapter.render_frame_host(),
39                                                 "tryPlayback();"));
40     run_loop.Run();
41   }
42 
NavigateFrameAndWait(content::RenderFrameHost * rfh,const GURL & url)43   void NavigateFrameAndWait(content::RenderFrameHost* rfh, const GURL& url) {
44     content::TestFrameNavigationObserver observer(rfh);
45     content::NavigationController::LoadURLParams params(url);
46     params.transition_type = ui::PAGE_TRANSITION_LINK;
47     params.frame_tree_node_id = rfh->GetFrameTreeNodeId();
48     content::WebContents::FromRenderFrameHost(rfh)
49         ->GetController()
50         .LoadURLWithParams(params);
51     observer.Wait();
52   }
53 
web_contents() const54   content::WebContents* web_contents() const {
55     return browser()->tab_strip_model()->GetActiveWebContents();
56   }
57 
first_child() const58   content::RenderFrameHost* first_child() const {
59     return web_contents()->GetAllFrames()[1];
60   }
61 
second_child() const62   content::RenderFrameHost* second_child() const {
63     return web_contents()->GetAllFrames()[2];
64   }
65 };
66 
67 // Flaky on various platforms. https://crbug.com/1101841
68 #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
69 #define MAYBE_RecordAutoplayAttemptUkm DISABLED_RecordAutoplayAttemptUkm
70 #else
71 #define MAYBE_RecordAutoplayAttemptUkm RecordAutoplayAttemptUkm
72 #endif
IN_PROC_BROWSER_TEST_F(AutoplayMetricsBrowserTest,MAYBE_RecordAutoplayAttemptUkm)73 IN_PROC_BROWSER_TEST_F(AutoplayMetricsBrowserTest,
74                        MAYBE_RecordAutoplayAttemptUkm) {
75   ukm::TestAutoSetUkmRecorder test_ukm_recorder;
76   GURL main_url(embedded_test_server()->GetURL("example.com",
77                                                "/media/autoplay_iframe.html"));
78   GURL foo_url(
79       embedded_test_server()->GetURL("foo.com", "/media/autoplay_iframe.html"));
80   GURL bar_url(
81       embedded_test_server()->GetURL("bar.com", "/media/autoplay_iframe.html"));
82 
83   // Navigate main frame, try play.
84   NavigateFrameAndWait(web_contents()->GetMainFrame(), main_url);
85   TryAutoplay(test_ukm_recorder, web_contents());
86 
87   // Check that we recorded a UKM event using the main frame URL.
88   {
89     auto ukm_entries = test_ukm_recorder.GetEntriesByName(Entry::kEntryName);
90 
91     ASSERT_EQ(1u, ukm_entries.size());
92     test_ukm_recorder.ExpectEntrySourceHasUrl(ukm_entries[0], main_url);
93   }
94 
95   // Navigate sub frame, try play.
96   NavigateFrameAndWait(first_child(), foo_url);
97   TryAutoplay(test_ukm_recorder, first_child());
98 
99   // Check that we recorded a UKM event that is not keyed to any URL.
100   {
101     auto ukm_entries = test_ukm_recorder.GetEntriesByName(Entry::kEntryName);
102 
103     ASSERT_EQ(2u, ukm_entries.size());
104     EXPECT_FALSE(
105         test_ukm_recorder.GetSourceForSourceId(ukm_entries[1]->source_id));
106 
107     // Check that a DocumentCreated entry was also created that was not keyed to
108     // any URL. However, we can use the navigation source ID to link this source
109     // to the top frame URL.
110     auto* dc_entry = test_ukm_recorder.GetDocumentCreatedEntryForSourceId(
111         ukm_entries[1]->source_id);
112     EXPECT_TRUE(dc_entry);
113     EXPECT_EQ(ukm_entries[1]->source_id, dc_entry->source_id);
114     EXPECT_FALSE(test_ukm_recorder.GetSourceForSourceId(dc_entry->source_id));
115     EXPECT_EQ(main_url,
116               test_ukm_recorder
117                   .GetSourceForSourceId(*test_ukm_recorder.GetEntryMetric(
118                       dc_entry, CreatedEntry::kNavigationSourceIdName))
119                   ->url());
120     EXPECT_EQ(0, *test_ukm_recorder.GetEntryMetric(
121                      dc_entry, CreatedEntry::kIsMainFrameName));
122   }
123 
124   // Navigate sub sub frame, try play.
125   NavigateFrameAndWait(second_child(), bar_url);
126   TryAutoplay(test_ukm_recorder, second_child());
127 
128   // Check that we recorded a UKM event that is not keyed to any url.
129   {
130     auto ukm_entries = test_ukm_recorder.GetEntriesByName(Entry::kEntryName);
131 
132     ASSERT_EQ(3u, ukm_entries.size());
133     EXPECT_FALSE(
134         test_ukm_recorder.GetSourceForSourceId(ukm_entries[2]->source_id));
135 
136     // Check that a DocumentCreated entry was also created that was not keyed to
137     // any URL. However, we can use the navigation source ID to link this source
138     // to the top frame URL.
139     auto* dc_entry = test_ukm_recorder.GetDocumentCreatedEntryForSourceId(
140         ukm_entries[2]->source_id);
141     EXPECT_TRUE(dc_entry);
142     EXPECT_EQ(ukm_entries[2]->source_id, dc_entry->source_id);
143     EXPECT_FALSE(test_ukm_recorder.GetSourceForSourceId(dc_entry->source_id));
144     EXPECT_EQ(main_url,
145               test_ukm_recorder
146                   .GetSourceForSourceId(*test_ukm_recorder.GetEntryMetric(
147                       dc_entry, CreatedEntry::kNavigationSourceIdName))
148                   ->url());
149     EXPECT_EQ(0, *test_ukm_recorder.GetEntryMetric(
150                      dc_entry, CreatedEntry::kIsMainFrameName));
151   }
152 
153   // Navigate top frame, try play.
154   NavigateFrameAndWait(web_contents()->GetMainFrame(), foo_url);
155   TryAutoplay(test_ukm_recorder, web_contents());
156 
157   // Check that we recorded a UKM event using the main frame URL.
158   {
159     auto ukm_entries = test_ukm_recorder.GetEntriesByName(Entry::kEntryName);
160 
161     ASSERT_EQ(4u, ukm_entries.size());
162     test_ukm_recorder.ExpectEntrySourceHasUrl(ukm_entries[3], foo_url);
163   }
164 }
165 
166 }  // namespace
167 
168 }  // namespace chrome
169