1 // Copyright 2024 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/dwa/dwa_service.h"
6
7 #include "base/test/scoped_feature_list.h"
8 #include "base/test/task_environment.h"
9 #include "base/time/time_override.h"
10 #include "components/metrics/dwa/dwa_entry_builder.h"
11 #include "components/metrics/dwa/dwa_pref_names.h"
12 #include "components/metrics/dwa/dwa_recorder.h"
13 #include "components/metrics/metrics_state_manager.h"
14 #include "components/metrics/test/test_metrics_service_client.h"
15 #include "components/prefs/pref_service.h"
16 #include "components/prefs/testing_pref_service.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace metrics::dwa {
20 class DwaServiceTest : public testing::Test {
21 public:
DwaServiceTest()22 DwaServiceTest() {
23 DwaRecorder::Get()->Purge();
24
25 MetricsStateManager::RegisterPrefs(prefs_.registry());
26 DwaService::RegisterPrefs(prefs_.registry());
27
28 scoped_feature_list_.InitAndEnableFeature(kDwaFeature);
29 }
30
31 DwaServiceTest(const DwaServiceTest&) = delete;
32 DwaServiceTest& operator=(const DwaServiceTest&) = delete;
33
34 ~DwaServiceTest() override = default;
35
TearDown()36 void TearDown() override { DwaRecorder::Get()->Purge(); }
37
GetPersistedLogCount()38 int GetPersistedLogCount() {
39 return prefs_.GetList(prefs::kUnsentLogStoreName).size();
40 }
41
42 protected:
43 // Check that the values in |coarse_system_info| are filled in and expected
44 // ones correspond to the test data.
CheckCoarseSystemInformation(const::dwa::CoarseSystemInfo & coarse_system_info)45 void CheckCoarseSystemInformation(
46 const ::dwa::CoarseSystemInfo& coarse_system_info) {
47 EXPECT_TRUE(coarse_system_info.has_channel());
48 // TestMetricsServiceClient::GetChannel() returns CHANNEL_BETA, so we should
49 // expect |coarse_system_info| channel to be "NOT_STABLE".
50 EXPECT_EQ(coarse_system_info.channel(),
51 ::dwa::CoarseSystemInfo::CHANNEL_NOT_STABLE);
52 EXPECT_TRUE(coarse_system_info.has_platform());
53 EXPECT_TRUE(coarse_system_info.has_geo_designation());
54 EXPECT_TRUE(coarse_system_info.has_client_age());
55 EXPECT_TRUE(coarse_system_info.has_milestone_prefix_trimmed());
56 EXPECT_TRUE(coarse_system_info.has_is_ukm_enabled());
57 }
58
59 // Records a test data DWA metric into DwaRecorder.
RecordTestMetric()60 void RecordTestMetric() {
61 ::dwa::DwaEntryBuilder builder("Kangaroo.Jumped");
62 builder.SetContent("adtech.com");
63 builder.SetMetric("Length", 5);
64 builder.Record(DwaRecorder::Get());
65 }
66
67 TestMetricsServiceClient client_;
68 TestingPrefServiceSimple prefs_;
69 base::test::ScopedFeatureList scoped_feature_list_;
70 };
71
72 class DwaServiceEnvironmentTest : public DwaServiceTest {
73 protected:
74 base::test::TaskEnvironment task_environment_{
75 base::test::TaskEnvironment::MainThreadType::UI,
76 base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED,
77 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
78 };
79
TEST_F(DwaServiceTest,RecordCoarseSystemInformation)80 TEST_F(DwaServiceTest, RecordCoarseSystemInformation) {
81 TestingPrefServiceSimple pref_service;
82 MetricsStateManager::RegisterPrefs(pref_service.registry());
83 ::dwa::CoarseSystemInfo coarse_system_info;
84 DwaService::RecordCoarseSystemInformation(client_, pref_service,
85 &coarse_system_info);
86 CheckCoarseSystemInformation(coarse_system_info);
87 }
88
TEST_F(DwaServiceTest,ClientIdIsGenerated)89 TEST_F(DwaServiceTest, ClientIdIsGenerated) {
90 TestingPrefServiceSimple pref_service;
91 DwaService::RegisterPrefs(pref_service.registry());
92
93 base::Time expected_time_at_daily_resolution;
94 EXPECT_TRUE(base::Time::FromString("1 May 2024 00:00:00 GMT",
95 &expected_time_at_daily_resolution));
96
97 uint64_t client_id;
98
99 {
100 base::subtle::ScopedTimeClockOverrides time_override(
101 []() {
102 base::Time now;
103 EXPECT_TRUE(base::Time::FromString("1 May 2024 12:15 GMT", &now));
104 return now;
105 },
106 nullptr, nullptr);
107 client_id = DwaService::GetEphemeralClientId(pref_service);
108 }
109
110 EXPECT_GT(pref_service.GetUint64(metrics::dwa::prefs::kDwaClientId), 0u);
111 EXPECT_EQ(client_id,
112 pref_service.GetUint64(metrics::dwa::prefs::kDwaClientId));
113 EXPECT_EQ(expected_time_at_daily_resolution,
114 pref_service.GetTime(metrics::dwa::prefs::kDwaClientIdLastUpdated));
115 }
116
TEST_F(DwaServiceTest,ClientIdOnlyChangesBetweenDays)117 TEST_F(DwaServiceTest, ClientIdOnlyChangesBetweenDays) {
118 TestingPrefServiceSimple pref_service;
119 DwaService::RegisterPrefs(pref_service.registry());
120
121 uint64_t client_id_day1;
122 uint64_t client_id_day2;
123 uint64_t client_id_day2_later;
124
125 {
126 base::subtle::ScopedTimeClockOverrides time_override(
127 []() {
128 base::Time now;
129 EXPECT_TRUE(base::Time::FromString("1 May 2024 12:15 GMT", &now));
130 return now;
131 },
132 nullptr, nullptr);
133 client_id_day1 = DwaService::GetEphemeralClientId(pref_service);
134 }
135
136 {
137 base::subtle::ScopedTimeClockOverrides time_override(
138 []() {
139 base::Time now;
140 EXPECT_TRUE(base::Time::FromString("2 May 2024 12:15 GMT", &now));
141 return now;
142 },
143 nullptr, nullptr);
144 client_id_day2 = DwaService::GetEphemeralClientId(pref_service);
145 }
146
147 {
148 base::subtle::ScopedTimeClockOverrides time_override(
149 []() {
150 base::Time now;
151 EXPECT_TRUE(base::Time::FromString("2 May 2024 16:15 GMT", &now));
152 return now;
153 },
154 nullptr, nullptr);
155 client_id_day2_later = DwaService::GetEphemeralClientId(pref_service);
156 }
157
158 EXPECT_NE(client_id_day1, client_id_day2);
159 EXPECT_EQ(client_id_day2, client_id_day2_later);
160 }
161
TEST_F(DwaServiceEnvironmentTest,Flush)162 TEST_F(DwaServiceEnvironmentTest, Flush) {
163 DwaService service(&client_, &prefs_);
164 DwaRecorder::Get()->EnableRecording();
165
166 // Tests Flush() when there are no page load events.
167 RecordTestMetric();
168 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
169 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
170
171 EXPECT_EQ(GetPersistedLogCount(), 0);
172 service.Flush(metrics::MetricsLogsEventManager::CreateReason::kPeriodic);
173 EXPECT_EQ(GetPersistedLogCount(), 0);
174
175 // Tests Flush() when there are page load events.
176 RecordTestMetric();
177 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
178 DwaRecorder::Get()->OnPageLoad();
179 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
180
181 EXPECT_EQ(GetPersistedLogCount(), 0);
182 service.Flush(metrics::MetricsLogsEventManager::CreateReason::kPeriodic);
183 EXPECT_EQ(GetPersistedLogCount(), 1);
184 }
185
TEST_F(DwaServiceEnvironmentTest,Purge)186 TEST_F(DwaServiceEnvironmentTest, Purge) {
187 DwaService service(&client_, &prefs_);
188 DwaRecorder::Get()->EnableRecording();
189
190 // Test that Purge() removes all metrics (entries and page load events).
191 RecordTestMetric();
192 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
193 DwaRecorder::Get()->OnPageLoad();
194 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
195 RecordTestMetric();
196 service.Purge();
197 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
198 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
199
200 // Test that Purge() removes all logs.
201 RecordTestMetric();
202 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
203 DwaRecorder::Get()->OnPageLoad();
204 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
205
206 EXPECT_EQ(GetPersistedLogCount(), 0);
207 service.Flush(metrics::MetricsLogsEventManager::CreateReason::kPeriodic);
208 EXPECT_EQ(GetPersistedLogCount(), 1);
209
210 service.Purge();
211 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
212 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
213 EXPECT_EQ(GetPersistedLogCount(), 0);
214 }
215
TEST_F(DwaServiceEnvironmentTest,EnableDisableRecordingAndReporting)216 TEST_F(DwaServiceEnvironmentTest, EnableDisableRecordingAndReporting) {
217 DwaService service(&client_, &prefs_);
218 EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
219
220 // When the reporting is enabled, the scheduler starts and creates tasks to
221 // rotate logs.
222 service.EnableReporting();
223 EXPECT_GE(task_environment_.GetPendingMainThreadTaskCount(), 1u);
224
225 service.DisableReporting();
226 EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
227
228 // Tests EnableRecording() records an entry.
229 DwaRecorder::Get()->EnableRecording();
230 RecordTestMetric();
231 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
232 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
233
234 // Save the above entry to memory as a page load event.
235 DwaRecorder::Get()->OnPageLoad();
236 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
237 EXPECT_EQ(GetPersistedLogCount(), 0);
238 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
239
240 // DisableRecording() and persist the above page load event to disk.
241 DwaRecorder::Get()->DisableRecording();
242 service.Flush(metrics::MetricsLogsEventManager::CreateReason::kPeriodic);
243 EXPECT_EQ(GetPersistedLogCount(), 1);
244 EXPECT_TRUE(service.unsent_log_store()->has_unsent_logs());
245
246 // Tests EnableRecording() with reporting_active() also starts
247 // DwaReportingService when there are unsent logs on disk.
248 service.EnableReporting();
249 DwaRecorder::Get()->EnableRecording();
250 // Validate there should be two pending tasks, one to rotate logs, and one to
251 // upload unsent logs from disk.
252 EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 2u);
253
254 base::TimeDelta upload_interval = client_.GetUploadInterval();
255 task_environment_.FastForwardBy(upload_interval);
256 EXPECT_TRUE(client_.uploader()->is_uploading());
257
258 // Simulate logs upload.
259 client_.uploader()->CompleteUpload(200);
260 EXPECT_FALSE(client_.uploader()->is_uploading());
261
262 // Logs are uploaded and there are no metrics in memory or on disk.
263 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
264 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
265 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
266 EXPECT_EQ(GetPersistedLogCount(), 0);
267
268 // Cleans up state of DwaService for the test following.
269 service.DisableReporting();
270 service.Purge();
271
272 // Tests DisableRecording() does not record an entry.
273 DwaRecorder::Get()->DisableRecording();
274 RecordTestMetric();
275 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
276 }
277
TEST_F(DwaServiceEnvironmentTest,LogsRotatedPeriodically)278 TEST_F(DwaServiceEnvironmentTest, LogsRotatedPeriodically) {
279 DwaService service(&client_, &prefs_);
280 DwaRecorder::Get()->EnableRecording();
281 service.EnableReporting();
282
283 RecordTestMetric();
284 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
285 DwaRecorder::Get()->OnPageLoad();
286
287 // Metrics are stored in memory as page load events in DwaRecorder, and there
288 // are no unsent logs.
289 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
290 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
291
292 // Metrics are stored in memory as unsent logs, and DwaRecorder is empty.
293 base::TimeDelta upload_interval = client_.GetUploadInterval();
294 task_environment_.FastForwardBy(upload_interval);
295 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
296 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
297 EXPECT_TRUE(service.unsent_log_store()->has_unsent_logs());
298 // PersistedLogCount is 0 because logs are stored in memory and not on disk.
299 EXPECT_EQ(GetPersistedLogCount(), 0);
300 EXPECT_TRUE(client_.uploader()->is_uploading());
301
302 // Simulate logs upload.
303 client_.uploader()->CompleteUpload(200);
304 EXPECT_FALSE(client_.uploader()->is_uploading());
305
306 // Logs are uploaded and there are no metrics in memory or on disk.
307 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
308 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
309 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
310 EXPECT_EQ(GetPersistedLogCount(), 0);
311
312 // Checks there is another rotation scheduled when the previous one finished.
313 EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1u);
314
315 // Repeat test above to validate the task scheduled is the task that rotates
316 // logs.
317 RecordTestMetric();
318 EXPECT_TRUE(DwaRecorder::Get()->HasEntries());
319 DwaRecorder::Get()->OnPageLoad();
320
321 EXPECT_TRUE(DwaRecorder::Get()->HasPageLoadEvents());
322 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
323
324 task_environment_.FastForwardBy(upload_interval);
325 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
326 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
327 EXPECT_TRUE(service.unsent_log_store()->has_unsent_logs());
328 EXPECT_EQ(GetPersistedLogCount(), 0);
329 EXPECT_TRUE(client_.uploader()->is_uploading());
330
331 client_.uploader()->CompleteUpload(200);
332 EXPECT_FALSE(client_.uploader()->is_uploading());
333
334 EXPECT_FALSE(DwaRecorder::Get()->HasEntries());
335 EXPECT_FALSE(DwaRecorder::Get()->HasPageLoadEvents());
336 EXPECT_FALSE(service.unsent_log_store()->has_unsent_logs());
337 EXPECT_EQ(GetPersistedLogCount(), 0);
338 }
339
340 } // namespace metrics::dwa
341