xref: /aosp_15_r20/external/cronet/components/metrics/structured/structured_metrics_service_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
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 "components/metrics/structured/structured_metrics_service.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/test/scoped_feature_list.h"
14 #include "base/test/task_environment.h"
15 #include "base/test/test_simple_task_runner.h"
16 #include "components/metrics/log_decoder.h"
17 #include "components/metrics/metrics_provider.h"
18 #include "components/metrics/structured/recorder.h"
19 #include "components/metrics/structured/reporting/structured_metrics_reporting_service.h"
20 #include "components/metrics/structured/structured_events.h"
21 #include "components/metrics/structured/structured_metrics_client.h"
22 #include "components/metrics/structured/structured_metrics_features.h"
23 #include "components/metrics/structured/structured_metrics_prefs.h"
24 #include "components/metrics/structured/structured_metrics_recorder.h"
25 #include "components/metrics/structured/test/test_event_storage.h"
26 #include "components/metrics/structured/test/test_key_data_provider.h"
27 #include "components/metrics/test/test_metrics_service_client.h"
28 #include "components/metrics/unsent_log_store.h"
29 #include "components/metrics/unsent_log_store_metrics_impl.h"
30 #include "components/prefs/testing_pref_service.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 
34 namespace metrics::structured {
35 namespace {
36 
37 using events::v2::test_project_one::TestEventOne;
38 using events::v2::test_project_six::TestEventSeven;
39 
40 // The name hash of "TestProjectOne".
41 constexpr uint64_t kProjectOneHash = UINT64_C(16881314472396226433);
42 // The name hash of "TestProjectThree".
43 constexpr uint64_t kProjectThreeHash = UINT64_C(10860358748803291132);
44 
45 class TestRecorder : public StructuredMetricsClient::RecordingDelegate {
46  public:
47   TestRecorder() = default;
48   TestRecorder(const TestRecorder& recorder) = delete;
49   TestRecorder& operator=(const TestRecorder& recorder) = delete;
50   ~TestRecorder() override = default;
51 
RecordEvent(Event && event)52   void RecordEvent(Event&& event) override {
53     Recorder::GetInstance()->RecordEvent(std::move(event));
54   }
55 
IsReadyToRecord() const56   bool IsReadyToRecord() const override { return true; }
57 };
58 
59 }  // namespace
60 
61 class StructuredMetricsServiceTest : public testing::Test {
62  public:
StructuredMetricsServiceTest()63   StructuredMetricsServiceTest() {
64     reporting::StructuredMetricsReportingService::RegisterPrefs(
65         prefs_.registry());
66   }
67 
SetUp()68   void SetUp() override {
69     feature_list_.InitWithFeatures({kEnabledStructuredMetricsService}, {});
70 
71     Recorder::GetInstance()->SetUiTaskRunner(
72         task_environment_.GetMainThreadTaskRunner());
73     StructuredMetricsClient::Get()->SetDelegate(&test_recorder_);
74 
75     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
76 
77     WriteTestingDeviceKeys();
78 
79     WriteTestingProfileKeys();
80   }
81 
TearDown()82   void TearDown() override { StructuredMetricsClient::Get()->UnsetDelegate(); }
83 
Init()84   void Init() {
85     auto key_data_provider = std::make_unique<TestKeyDataProvider>(
86         DeviceKeyFilePath(), ProfileKeyFilePath());
87     TestKeyDataProvider* test_key_data_provider = key_data_provider.get();
88     auto recorder = std::make_unique<StructuredMetricsRecorder>(
89         std::move(key_data_provider), std::make_unique<TestEventStorage>());
90 
91     // Register the profile with the key data provider.
92     test_key_data_provider->OnProfileAdded(temp_dir_.GetPath());
93 
94     service_ = std::make_unique<StructuredMetricsService>(&client_, &prefs_,
95                                                           std::move(recorder));
96     Wait();
97   }
98 
EnableRecording()99   void EnableRecording() { service_->EnableRecording(); }
EnableReporting()100   void EnableReporting() { service_->EnableReporting(); }
101 
DisableRecording()102   void DisableRecording() { service_->DisableRecording(); }
DisableReporting()103   void DisableReporting() { service_->DisableReporting(); }
104 
ProfileKeyFilePath()105   base::FilePath ProfileKeyFilePath() {
106     return temp_dir_.GetPath()
107         .Append(FILE_PATH_LITERAL("structured_metrics"))
108         .Append(FILE_PATH_LITERAL("keys"));
109   }
110 
DeviceKeyFilePath()111   base::FilePath DeviceKeyFilePath() {
112     return temp_dir_.GetPath()
113         .Append(FILE_PATH_LITERAL("structured_metrics"))
114         .Append(FILE_PATH_LITERAL("device_keys"));
115   }
116 
DeviceEventsFilePath()117   base::FilePath DeviceEventsFilePath() {
118     return temp_dir_.GetPath()
119         .Append(FILE_PATH_LITERAL("structured_metrics"))
120         .Append(FILE_PATH_LITERAL("events"));
121   }
122 
WriteTestingProfileKeys()123   void WriteTestingProfileKeys() {
124     const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
125 
126     KeyDataProto proto;
127     KeyProto& key_one = (*proto.mutable_keys())[kProjectOneHash];
128     key_one.set_key("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
129     key_one.set_last_rotation(today);
130     key_one.set_rotation_period(90);
131 
132     KeyProto& key_three = (*proto.mutable_keys())[kProjectThreeHash];
133     key_three.set_key("cccccccccccccccccccccccccccccccc");
134     key_three.set_last_rotation(today);
135     key_three.set_rotation_period(90);
136 
137     base::CreateDirectory(ProfileKeyFilePath().DirName());
138     ASSERT_TRUE(
139         base::WriteFile(ProfileKeyFilePath(), proto.SerializeAsString()));
140     Wait();
141   }
142 
WriteTestingDeviceKeys()143   void WriteTestingDeviceKeys() {
144     base::CreateDirectory(DeviceKeyFilePath().DirName());
145     ASSERT_TRUE(base::WriteFile(DeviceKeyFilePath(),
146                                 KeyDataProto().SerializeAsString()));
147     Wait();
148   }
149 
GetPersistedLogCount()150   int GetPersistedLogCount() {
151     return prefs_.GetList(prefs::kLogStoreName).size();
152   }
153 
GetPersistedLog()154   ChromeUserMetricsExtension GetPersistedLog() {
155     EXPECT_THAT(GetPersistedLogCount(), 1);
156     metrics::UnsentLogStore result_unsent_log_store(
157         std::make_unique<UnsentLogStoreMetricsImpl>(), &prefs_,
158         prefs::kLogStoreName, /*metadata_pref_name=*/nullptr,
159         // Set to 3 so logs are not dropped in the test.
160         UnsentLogStore::UnsentLogStoreLimits{
161             .min_log_count = 3,
162         },
163         /*signing_key=*/std::string(),
164         /*logs_event_manager=*/nullptr);
165 
166     result_unsent_log_store.LoadPersistedUnsentLogs();
167     result_unsent_log_store.StageNextLog();
168 
169     ChromeUserMetricsExtension uma_proto;
170     EXPECT_TRUE(metrics::DecodeLogDataToProto(
171         result_unsent_log_store.staged_log(), &uma_proto));
172     return uma_proto;
173   }
174 
service()175   StructuredMetricsService& service() { return *service_.get(); }
176 
Wait()177   void Wait() { task_environment_.RunUntilIdle(); }
178 
AdvanceClock(int hours)179   void AdvanceClock(int hours) {
180     task_environment_.AdvanceClock(base::Hours(hours));
181   }
182 
183  protected:
184   std::unique_ptr<StructuredMetricsService> service_;
185   metrics::TestMetricsServiceClient client_;
186 
187  private:
188   base::test::ScopedFeatureList feature_list_;
189   TestingPrefServiceSimple prefs_;
190 
191   TestRecorder test_recorder_;
192   base::ScopedTempDir temp_dir_;
193 
194   base::test::TaskEnvironment task_environment_{
195       base::test::TaskEnvironment::MainThreadType::UI,
196       base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED,
197       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
198 };
199 
TEST_F(StructuredMetricsServiceTest,PurgeInMemory)200 TEST_F(StructuredMetricsServiceTest, PurgeInMemory) {
201   Init();
202 
203   EnableRecording();
204   EnableReporting();
205 
206   StructuredMetricsClient::Record(
207       std::move(TestEventOne().SetTestMetricTwo(1)));
208   StructuredMetricsClient::Record(
209       std::move(TestEventSeven().SetTestMetricSeven(1.0)));
210 
211   service_->Purge();
212   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
213 
214   // Nothing should be stored.
215   EXPECT_THAT(GetPersistedLogCount(), 0);
216 }
217 
TEST_F(StructuredMetricsServiceTest,PurgePersisted)218 TEST_F(StructuredMetricsServiceTest, PurgePersisted) {
219   Init();
220 
221   EnableRecording();
222   EnableReporting();
223 
224   StructuredMetricsClient::Record(
225       std::move(TestEventOne().SetTestMetricTwo(1)));
226   StructuredMetricsClient::Record(
227       std::move(TestEventSeven().SetTestMetricSeven(1.0)));
228 
229   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
230 
231   service_->Purge();
232 
233   // Need to make sure there is a log to read.
234   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
235 
236   // Nothing should be stored.
237   EXPECT_THAT(GetPersistedLogCount(), 0);
238 }
239 
TEST_F(StructuredMetricsServiceTest,RotateLogs)240 TEST_F(StructuredMetricsServiceTest, RotateLogs) {
241   Init();
242 
243   EnableRecording();
244   EnableReporting();
245 
246   StructuredMetricsClient::Record(
247       std::move(TestEventOne().SetTestMetricTwo(1)));
248   StructuredMetricsClient::Record(
249       std::move(TestEventSeven().SetTestMetricSeven(1)));
250 
251   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
252 
253   const auto uma_proto = GetPersistedLog();
254   EXPECT_THAT(uma_proto.structured_data().events().size(), 2);
255 }
256 
TEST_F(StructuredMetricsServiceTest,SystemProfileFilled)257 TEST_F(StructuredMetricsServiceTest, SystemProfileFilled) {
258   Init();
259 
260   EnableRecording();
261   EnableReporting();
262 
263   StructuredMetricsClient::Record(
264       std::move(TestEventOne().SetTestMetricTwo(1)));
265   StructuredMetricsClient::Record(
266       std::move(TestEventSeven().SetTestMetricSeven(1)));
267 
268   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
269 
270   const auto uma_proto = GetPersistedLog();
271   EXPECT_THAT(uma_proto.structured_data().events().size(), 2);
272   EXPECT_TRUE(uma_proto.has_system_profile());
273 
274   const SystemProfileProto& system_profile = uma_proto.system_profile();
275   EXPECT_EQ(system_profile.channel(), client_.GetChannel());
276   EXPECT_EQ(system_profile.app_version(), client_.GetVersionString());
277 }
278 
TEST_F(StructuredMetricsServiceTest,DoesNotRecordWhenRecordingDisabled)279 TEST_F(StructuredMetricsServiceTest, DoesNotRecordWhenRecordingDisabled) {
280   Init();
281   EnableRecording();
282   EnableReporting();
283 
284   StructuredMetricsClient::Record(
285       std::move(TestEventOne().SetTestMetricTwo(1)));
286   StructuredMetricsClient::Record(
287       std::move(TestEventSeven().SetTestMetricSeven(1)));
288 
289   DisableRecording();
290 
291   StructuredMetricsClient::Record(
292       std::move(TestEventOne().SetTestMetricTwo(1)));
293   StructuredMetricsClient::Record(
294       std::move(TestEventSeven().SetTestMetricSeven(1)));
295 
296   EnableRecording();
297 
298   service_->Flush(metrics::MetricsLogsEventManager::CreateReason::kUnknown);
299 
300   const auto uma_proto = GetPersistedLog();
301   EXPECT_THAT(uma_proto.structured_data().events().size(), 2);
302 }
303 
TEST_F(StructuredMetricsServiceTest,FlushOnShutdown)304 TEST_F(StructuredMetricsServiceTest, FlushOnShutdown) {
305   Init();
306   EnableRecording();
307   EnableReporting();
308 
309   StructuredMetricsClient::Record(
310       std::move(TestEventOne().SetTestMetricTwo(1)));
311   StructuredMetricsClient::Record(
312       std::move(TestEventSeven().SetTestMetricSeven(1)));
313 
314   // Will flush the log.
315   service_.reset();
316 
317   const auto uma_proto = GetPersistedLog();
318   EXPECT_THAT(uma_proto.structured_data().events().size(), 2);
319 }
320 
321 }  // namespace metrics::structured
322