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