test_ukm_recorder.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright 2017 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. #include "components/ukm/test_ukm_recorder.h"
  5. #include <algorithm>
  6. #include <iterator>
  7. #include "base/check_op.h"
  8. #include "base/metrics/metrics_hashes.h"
  9. #include "base/threading/sequenced_task_runner_handle.h"
  10. #include "services/metrics/public/cpp/delegating_ukm_recorder.h"
  11. #include "services/metrics/public/cpp/ukm_builders.h"
  12. #include "services/metrics/public/cpp/ukm_source.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace ukm {
  15. namespace {
  16. // Merge the data from |in| to |out|.
  17. void MergeEntry(const mojom::UkmEntry* in, mojom::UkmEntry* out) {
  18. if (out->event_hash) {
  19. EXPECT_EQ(out->source_id, in->source_id);
  20. EXPECT_EQ(out->event_hash, in->event_hash);
  21. } else {
  22. out->event_hash = in->event_hash;
  23. out->source_id = in->source_id;
  24. }
  25. for (const auto& metric : in->metrics) {
  26. out->metrics.emplace(metric);
  27. }
  28. }
  29. } // namespace
  30. TestUkmRecorder::TestUkmRecorder() {
  31. EnableRecording(/*extensions=*/true);
  32. InitDecodeMap();
  33. SetSamplingForTesting(1); // 1-in-1 == unsampled
  34. }
  35. TestUkmRecorder::~TestUkmRecorder() {}
  36. bool TestUkmRecorder::ShouldRestrictToWhitelistedSourceIds() const {
  37. // In tests, we want to record all source ids (not just those that are
  38. // whitelisted).
  39. return false;
  40. }
  41. void TestUkmRecorder::AddEntry(mojom::UkmEntryPtr entry) {
  42. const bool should_run_callback =
  43. on_add_entry_ && entry && entry_hash_to_wait_for_ == entry->event_hash;
  44. UkmRecorderImpl::AddEntry(std::move(entry));
  45. if (should_run_callback)
  46. on_add_entry_.Run();
  47. }
  48. const UkmSource* TestUkmRecorder::GetSourceForSourceId(
  49. SourceId source_id) const {
  50. const UkmSource* source = nullptr;
  51. for (const auto& kv : sources()) {
  52. if (kv.second->id() == source_id) {
  53. DCHECK_EQ(nullptr, source);
  54. source = kv.second.get();
  55. }
  56. }
  57. return source;
  58. }
  59. const ukm::mojom::UkmEntry* TestUkmRecorder::GetDocumentCreatedEntryForSourceId(
  60. ukm::SourceId source_id) const {
  61. auto entries = GetEntriesByName(ukm::builders::DocumentCreated::kEntryName);
  62. for (auto* entry : entries) {
  63. if (entry->source_id == source_id)
  64. return entry;
  65. }
  66. return nullptr;
  67. }
  68. void TestUkmRecorder::SetOnAddEntryCallback(
  69. base::StringPiece entry_name,
  70. base::RepeatingClosure on_add_entry) {
  71. on_add_entry_ = std::move(on_add_entry);
  72. entry_hash_to_wait_for_ = base::HashMetricName(entry_name);
  73. }
  74. std::vector<const mojom::UkmEntry*> TestUkmRecorder::GetEntriesByName(
  75. base::StringPiece entry_name) const {
  76. uint64_t hash = base::HashMetricName(entry_name);
  77. std::vector<const mojom::UkmEntry*> result;
  78. for (const auto& it : entries()) {
  79. if (it->event_hash == hash)
  80. result.push_back(it.get());
  81. }
  82. return result;
  83. }
  84. std::map<ukm::SourceId, mojom::UkmEntryPtr>
  85. TestUkmRecorder::GetMergedEntriesByName(base::StringPiece entry_name) const {
  86. uint64_t hash = base::HashMetricName(entry_name);
  87. std::map<ukm::SourceId, mojom::UkmEntryPtr> result;
  88. for (const auto& it : entries()) {
  89. if (it->event_hash != hash)
  90. continue;
  91. mojom::UkmEntryPtr& entry_ptr = result[it->source_id];
  92. if (!entry_ptr)
  93. entry_ptr = mojom::UkmEntry::New();
  94. MergeEntry(it.get(), entry_ptr.get());
  95. }
  96. return result;
  97. }
  98. void TestUkmRecorder::ExpectEntrySourceHasUrl(const mojom::UkmEntry* entry,
  99. const GURL& url) const {
  100. const UkmSource* src = GetSourceForSourceId(entry->source_id);
  101. if (src == nullptr) {
  102. FAIL() << "Entry source id has no associated Source.";
  103. }
  104. EXPECT_EQ(src->url(), url);
  105. }
  106. // static
  107. bool TestUkmRecorder::EntryHasMetric(const mojom::UkmEntry* entry,
  108. base::StringPiece metric_name) {
  109. return GetEntryMetric(entry, metric_name) != nullptr;
  110. }
  111. // static
  112. const int64_t* TestUkmRecorder::GetEntryMetric(const mojom::UkmEntry* entry,
  113. base::StringPiece metric_name) {
  114. uint64_t hash = base::HashMetricName(metric_name);
  115. const auto it = entry->metrics.find(hash);
  116. if (it != entry->metrics.end())
  117. return &it->second;
  118. return nullptr;
  119. }
  120. // static
  121. void TestUkmRecorder::ExpectEntryMetric(const mojom::UkmEntry* entry,
  122. base::StringPiece metric_name,
  123. int64_t expected_value) {
  124. const int64_t* metric = GetEntryMetric(entry, metric_name);
  125. if (metric == nullptr) {
  126. FAIL() << "Failed to find metric for event: " << metric_name;
  127. }
  128. EXPECT_EQ(expected_value, *metric) << " for metric:" << metric_name;
  129. }
  130. TestAutoSetUkmRecorder::TestAutoSetUkmRecorder() {
  131. DelegatingUkmRecorder::Get()->AddDelegate(self_ptr_factory_.GetWeakPtr());
  132. }
  133. TestAutoSetUkmRecorder::~TestAutoSetUkmRecorder() {
  134. DelegatingUkmRecorder::Get()->RemoveDelegate(this);
  135. }
  136. std::vector<TestUkmRecorder::HumanReadableUkmMetrics>
  137. TestUkmRecorder::GetMetrics(
  138. std::string entry_name,
  139. const std::vector<std::string>& metric_names) const {
  140. std::vector<TestUkmRecorder::HumanReadableUkmMetrics> result;
  141. for (const auto& entry : GetEntries(entry_name, metric_names)) {
  142. result.push_back(entry.metrics);
  143. }
  144. return result;
  145. }
  146. std::vector<TestUkmRecorder::HumanReadableUkmEntry> TestUkmRecorder::GetEntries(
  147. std::string entry_name,
  148. const std::vector<std::string>& metric_names) const {
  149. std::vector<TestUkmRecorder::HumanReadableUkmEntry> results;
  150. for (const ukm::mojom::UkmEntry* entry : GetEntriesByName(entry_name)) {
  151. HumanReadableUkmEntry result;
  152. result.source_id = entry->source_id;
  153. for (const std::string& metric_name : metric_names) {
  154. const int64_t* metric_value =
  155. ukm::TestUkmRecorder::GetEntryMetric(entry, metric_name);
  156. if (metric_value)
  157. result.metrics[metric_name] = *metric_value;
  158. }
  159. results.push_back(std::move(result));
  160. }
  161. return results;
  162. }
  163. std::vector<ukm::TestAutoSetUkmRecorder::HumanReadableUkmMetrics>
  164. TestUkmRecorder::FilteredHumanReadableMetricForEntry(
  165. const std::string& entry_name,
  166. const std::string& metric_name) const {
  167. std::vector<std::string> metric_name_vector(1, metric_name);
  168. auto metrics = GetMetrics(entry_name, metric_name_vector);
  169. std::vector<ukm::TestAutoSetUkmRecorder::HumanReadableUkmMetrics>
  170. filtered_result;
  171. std::copy_if(
  172. metrics.begin(), metrics.end(), std::back_inserter(filtered_result),
  173. [&metric_name](
  174. ukm::TestAutoSetUkmRecorder::HumanReadableUkmMetrics metric) {
  175. if (metric.empty())
  176. return false;
  177. return metric.begin()->first == metric_name;
  178. });
  179. return filtered_result;
  180. }
  181. TestUkmRecorder::HumanReadableUkmEntry::HumanReadableUkmEntry() = default;
  182. TestUkmRecorder::HumanReadableUkmEntry::HumanReadableUkmEntry(
  183. ukm::SourceId source_id,
  184. TestUkmRecorder::HumanReadableUkmMetrics ukm_metrics)
  185. : source_id(source_id), metrics(std::move(ukm_metrics)) {}
  186. TestUkmRecorder::HumanReadableUkmEntry::HumanReadableUkmEntry(
  187. const HumanReadableUkmEntry&) = default;
  188. TestUkmRecorder::HumanReadableUkmEntry::~HumanReadableUkmEntry() = default;
  189. bool TestUkmRecorder::HumanReadableUkmEntry::operator==(
  190. const HumanReadableUkmEntry& other) const {
  191. return source_id == other.source_id && metrics == other.metrics;
  192. }
  193. } // namespace ukm