1 // Copyright 2020 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 "chrome/browser/extensions/identifiability_metrics_test_util.h"
6 
7 #include "base/run_loop.h"
8 #include "chrome/common/privacy_budget/scoped_privacy_budget_config.h"
9 #include "components/ukm/test_ukm_recorder.h"
10 #include "content/public/test/browser_test_utils.h"
11 #include "extensions/common/identifiability_metrics.h"
12 #include "services/metrics/public/cpp/ukm_builders.h"
13 #include "services/metrics/public/cpp/ukm_recorder.h"
14 #include "third_party/blink/public/common/privacy_budget/identifiability_sample_collector.h"
15 
16 namespace extensions {
17 
IdentifiabilityMetricsTestHelper()18 IdentifiabilityMetricsTestHelper::IdentifiabilityMetricsTestHelper() {
19   privacy_budget_config_.Apply(test::ScopedPrivacyBudgetConfig::Parameters());
20 }
21 
22 IdentifiabilityMetricsTestHelper::~IdentifiabilityMetricsTestHelper() = default;
23 
SetUpOnMainThread()24 void IdentifiabilityMetricsTestHelper::SetUpOnMainThread() {
25   ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
26 }
27 
PrepareForTest(base::RunLoop * run_loop)28 void IdentifiabilityMetricsTestHelper::PrepareForTest(base::RunLoop* run_loop) {
29   DCHECK(ukm_recorder_) << "IdentifiabilityMetricsTestHelper::"
30                            "SetUpOnMainThread hasn't been called";
31   ukm_recorder_->SetOnAddEntryCallback(
32       ukm::builders::Identifiability::kEntryName, run_loop->QuitClosure());
33 }
34 
35 std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr>
NavigateToBlankAndWaitForMetrics(content::WebContents * contents,base::RunLoop * run_loop)36 IdentifiabilityMetricsTestHelper::NavigateToBlankAndWaitForMetrics(
37     content::WebContents* contents,
38     base::RunLoop* run_loop) {
39   DCHECK(ukm_recorder_) << "IdentifiabilityMetricsTestHelper::"
40                            "SetUpOnMainThread hasn't been called";
41 
42   // Need to navigate away to force a metrics flush; otherwise it would be
43   // dependent on periodic flush heuristics.
44   content::NavigateToURLBlockUntilNavigationsComplete(contents,
45                                                       GURL("about:blank"), 1);
46 
47   // Also force a browser-side flush.
48   blink::IdentifiabilitySampleCollector::Get()->Flush(ukm::UkmRecorder::Get());
49 
50   run_loop->Run();
51   return ukm_recorder_->GetMergedEntriesByName(
52       ukm::builders::Identifiability::kEntryName);
53 }
54 
EnsureIdentifiabilityEventGenerated(content::WebContents * contents)55 void IdentifiabilityMetricsTestHelper::EnsureIdentifiabilityEventGenerated(
56     content::WebContents* contents) {
57   // Create a canvas and serialize it to force at least one event to happen,
58   // since otherwise there is no way to synchronize with the renderer.
59   constexpr char kForceMetricScript[] =
60       R"(
61         var c = document.createElement("canvas");
62         document.body.appendChild(c);
63         var ctx = c.getContext("2d");
64         var url = c.toDataURL();
65       )";
66   // This uses ExecuteScript since some tests have CSP restrictions on JS
67   // execution that would block ExecJS.
68   EXPECT_TRUE(content::ExecuteScript(contents, kForceMetricScript));
69 }
70 
71 // static
ContainsSurfaceOfType(const std::map<ukm::SourceId,ukm::mojom::UkmEntryPtr> & merged_entries,blink::IdentifiableSurface::Type type)72 bool IdentifiabilityMetricsTestHelper::ContainsSurfaceOfType(
73     const std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr>& merged_entries,
74     blink::IdentifiableSurface::Type type) {
75   for (const auto& entry : merged_entries) {
76     const auto& metrics = entry.second->metrics;
77     for (const auto& surface_value : metrics) {
78       if (blink::IdentifiableSurface::FromMetricHash(surface_value.first)
79               .GetType() == type) {
80         return true;
81       }
82     }
83   }
84   return false;
85 }
86 
87 // static
88 std::set<ukm::SourceId>
GetSourceIDsForSurfaceAndExtension(const std::map<ukm::SourceId,ukm::mojom::UkmEntryPtr> & merged_entries,blink::IdentifiableSurface::Type type,const ExtensionId & extension_id)89 IdentifiabilityMetricsTestHelper::GetSourceIDsForSurfaceAndExtension(
90     const std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr>& merged_entries,
91     blink::IdentifiableSurface::Type type,
92     const ExtensionId& extension_id) {
93   std::set<ukm::SourceId> result;
94   for (const auto& entry : merged_entries) {
95     const auto& metrics = entry.second->metrics;
96     if (metrics.contains(
97             SurfaceForExtension(type, extension_id).ToUkmMetricHash())) {
98       result.insert(entry.first);
99     }
100   }
101   return result;
102 }
103 
104 }  // namespace extensions
105