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