1 // Copyright 2019 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_provider.h"
6 #include <cstdint>
7
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/test/bind.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "base/test/scoped_feature_list.h"
15 #include "base/test/task_environment.h"
16 #include "base/threading/scoped_blocking_call.h"
17 #include "components/metrics/structured/event.h"
18 #include "components/metrics/structured/recorder.h"
19 #include "components/metrics/structured/storage.pb.h"
20 #include "components/metrics/structured/structured_events.h"
21 #include "components/metrics/structured/structured_metrics_features.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
24
25 namespace metrics::structured {
26
27 namespace {
28
29 // These project, event, and metric names are used for testing.
30
31 // The name hash of "TestProjectOne".
32 constexpr uint64_t kProjectOneHash = UINT64_C(16881314472396226433);
33 // The name hash of "TestProjectTwo".
34 constexpr uint64_t kProjectTwoHash = UINT64_C(5876808001962504629);
35 // The name hash of "TestProjectThree".
36 constexpr uint64_t kProjectThreeHash = UINT64_C(10860358748803291132);
37 // The name hash of "TestProjectFour".
38 constexpr uint64_t kProjectFourHash = UINT64_C(6801665881746546626);
39 // The name hash of "TestProjectFive"
40 constexpr uint64_t kProjectFiveHash = UINT64_C(3960582687892677139);
41 // The name hash of "TestProjectSix"
42 constexpr uint64_t kProjectSixHash = UINT64_C(6972396123792667134);
43 // The name hash of "CrOSEvents"
44 constexpr uint64_t kCrOSEventsProjectHash = UINT64_C(12657197978410187837);
45
46 // The name hash of "chrome::TestProjectOne::TestEventOne".
47 constexpr uint64_t kEventOneHash = UINT64_C(13593049295042080097);
48 // The name hash of "chrome::TestProjectTwo::TestEventTwo".
49 constexpr uint64_t kEventTwoHash = UINT64_C(8995967733561999410);
50 // The name hash of "chrome::TestProjectTwo::TestEventThree".
51 constexpr uint64_t kEventThreeHash = UINT64_C(5848687377041124372);
52 // The name hash of "chrome::TestProjectThree::TestEventFour".
53 constexpr uint64_t kEventFourHash = UINT64_C(1718797808092246258);
54 // The name hash of "chrome::TestProjectFour::TestEventFive".
55 constexpr uint64_t kEventFiveHash = UINT64_C(7045523601811399253);
56 // The name hash of "chrome::TestProjectFour::TestEventSix".
57 constexpr uint64_t kEventSixHash = UINT64_C(2873337042686447043);
58 // The name hash of "chrome::TestProjectSix::TestEventSeven".
59 constexpr uint64_t kEventSevenHash = UINT64_C(16749091071228286247);
60 // The name hash of "chrome::CrOSEvents::NoMetricsEvent".
61 constexpr uint64_t kNoMetricsEventHash = UINT64_C(5106854608989380457);
62
63 // The name hash of "TestMetricOne".
64 constexpr uint64_t kMetricOneHash = UINT64_C(637929385654885975);
65 // The name hash of "TestMetricTwo".
66 constexpr uint64_t kMetricTwoHash = UINT64_C(14083999144141567134);
67 // The name hash of "TestMetricThree".
68 constexpr uint64_t kMetricThreeHash = UINT64_C(13469300759843809564);
69 // The name hash of "TestMetricFour".
70 constexpr uint64_t kMetricFourHash = UINT64_C(2917855408523247722);
71 // The name hash of "TestMetricFive".
72 constexpr uint64_t kMetricFiveHash = UINT64_C(8665976921794972190);
73 // The name hash of "TestMetricSix".
74 constexpr uint64_t kMetricSixHash = UINT64_C(3431522567539822144);
75 // The name hash of "TestMetricSeven".
76 constexpr uint64_t kMetricSevenHash = UINT64_C(8395865158198697574);
77
78 // The hex-encoded first 8 bytes of SHA256("aaa...a")
79 constexpr char kProjectOneId[] = "3BA3F5F43B926026";
80 // The hex-encoded first 8 bytes of SHA256("bbb...b")
81 constexpr char kProjectTwoId[] = "BDB339768BC5E4FE";
82 // The hex-encoded first 8 bytes of SHA256("ddd...d")
83 constexpr char kProjectFourId[] = "FBBBB6DE2AA74C3C";
84
85 // Test values.
86 constexpr char kValueOne[] = "value one";
87 constexpr char kValueTwo[] = "value two";
88
89 constexpr char kHwid[] = "hwid";
90 constexpr size_t kUserCount = 3;
91
HashToHex(const uint64_t hash)92 std::string HashToHex(const uint64_t hash) {
93 return base::HexEncode(&hash, sizeof(uint64_t));
94 }
95
96 // Make a simple testing proto with one |uma_events| message for each id in
97 // |ids|.
MakeExternalEventProto(const std::vector<uint64_t> & ids)98 EventsProto MakeExternalEventProto(const std::vector<uint64_t>& ids) {
99 EventsProto proto;
100
101 for (const auto id : ids) {
102 auto* event = proto.add_uma_events();
103 event->set_profile_event_id(id);
104 }
105
106 return proto;
107 }
108
109 class TestRecorder : public StructuredMetricsClient::RecordingDelegate {
110 public:
111 TestRecorder() = default;
112 TestRecorder(const TestRecorder& recorder) = delete;
113 TestRecorder& operator=(const TestRecorder& recorder) = delete;
114 ~TestRecorder() override = default;
115
RecordEvent(Event && event)116 void RecordEvent(Event&& event) override {
117 Recorder::GetInstance()->RecordEvent(std::move(event));
118 }
119
IsReadyToRecord() const120 bool IsReadyToRecord() const override { return true; }
121 };
122
123 class TestSystemProfileProvider : public metrics::MetricsProvider {
124 public:
125 TestSystemProfileProvider() = default;
126 TestSystemProfileProvider(const TestSystemProfileProvider& recorder) = delete;
127 TestSystemProfileProvider& operator=(
128 const TestSystemProfileProvider& recorder) = delete;
129 ~TestSystemProfileProvider() override = default;
130
ProvideSystemProfileMetrics(metrics::SystemProfileProto * proto)131 void ProvideSystemProfileMetrics(
132 metrics::SystemProfileProto* proto) override {
133 proto->set_multi_profile_user_count(kUserCount);
134 proto->mutable_hardware()->set_full_hardware_class(kHwid);
135 }
136 };
137
138 } // namespace
139
140 class StructuredMetricsProviderTest : public testing::Test {
141 protected:
SetUp()142 void SetUp() override {
143 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
144 Recorder::GetInstance()->SetUiTaskRunner(
145 task_environment_.GetMainThreadTaskRunner());
146 StructuredMetricsClient::Get()->SetDelegate(&recorder_);
147 // Move the mock date forward from day 0, because KeyData assumes that day 0
148 // is a bug.
149 task_environment_.AdvanceClock(base::Days(1000));
150 }
151
TempDirPath()152 base::FilePath TempDirPath() { return temp_dir_.GetPath(); }
153
ProfileKeyFilePath()154 base::FilePath ProfileKeyFilePath() {
155 return temp_dir_.GetPath().Append("structured_metrics").Append("keys");
156 }
157
DeviceKeyFilePath()158 base::FilePath DeviceKeyFilePath() {
159 return temp_dir_.GetPath()
160 .Append("structured_metrics")
161 .Append("device_keys");
162 }
163
Wait()164 void Wait() { task_environment_.RunUntilIdle(); }
165
WriteTestingProfileKeys()166 void WriteTestingProfileKeys() {
167 const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
168
169 KeyDataProto proto;
170 KeyProto& key_one = (*proto.mutable_keys())[kProjectOneHash];
171 key_one.set_key("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
172 key_one.set_last_rotation(today);
173 key_one.set_rotation_period(90);
174
175 KeyProto& key_two = (*proto.mutable_keys())[kProjectTwoHash];
176 key_two.set_key("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
177 key_two.set_last_rotation(today);
178 key_two.set_rotation_period(90);
179
180 KeyProto& key_three = (*proto.mutable_keys())[kProjectThreeHash];
181 key_three.set_key("cccccccccccccccccccccccccccccccc");
182 key_three.set_last_rotation(today);
183 key_three.set_rotation_period(90);
184
185 base::CreateDirectory(ProfileKeyFilePath().DirName());
186 ASSERT_TRUE(
187 base::WriteFile(ProfileKeyFilePath(), proto.SerializeAsString()));
188 Wait();
189 }
190
WriteTestingDeviceKeys()191 void WriteTestingDeviceKeys() {
192 const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
193
194 KeyDataProto proto;
195 KeyProto& key = (*proto.mutable_keys())[kProjectFourHash];
196 key.set_key("dddddddddddddddddddddddddddddddd");
197 key.set_last_rotation(today);
198 key.set_rotation_period(90);
199
200 base::CreateDirectory(DeviceKeyFilePath().DirName());
201 ASSERT_TRUE(
202 base::WriteFile(DeviceKeyFilePath(), proto.SerializeAsString()));
203 Wait();
204 }
205
ReadKeys(const base::FilePath & filepath)206 KeyDataProto ReadKeys(const base::FilePath& filepath) {
207 base::ScopedBlockingCall scoped_blocking_call(
208 FROM_HERE, base::BlockingType::MAY_BLOCK);
209 Wait();
210 CHECK(base::PathExists(filepath));
211
212 std::string proto_str;
213 CHECK(base::ReadFileToString(filepath, &proto_str));
214
215 KeyDataProto proto;
216 CHECK(proto.ParseFromString(proto_str));
217 return proto;
218 }
219
220 // Adds a project to the disallowed projects list.
AddDisallowedProject(uint64_t project_name_hash)221 void AddDisallowedProject(uint64_t project_name_hash) {
222 provider_->AddDisallowedProjectForTest(project_name_hash);
223 }
224
225 // Simulates the three external events that the structure metrics system cares
226 // about: the metrics service initializing and enabling its providers, and a
227 // user logging in.
Init()228 void Init() {
229 // Create a system profile, normally done by ChromeMetricsServiceClient.
230 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
231 // Create the provider, normally done by the ChromeMetricsServiceClient.
232 provider_ = std::unique_ptr<StructuredMetricsProvider>(
233 new StructuredMetricsProvider(
234 DeviceKeyFilePath(),
235 /*write_delay=*/base::Seconds(0),
236 /*min_independent_metrics_interval=*/base::Seconds(0),
237 system_profile_provider_.get()));
238 // Enable recording, normally done after the metrics service has checked
239 // consent allows recording.
240 provider_->OnRecordingEnabled();
241 // Add a profile, normally done by the ChromeMetricsServiceClient after a
242 // user logs in.
243 provider_->OnProfileAdded(TempDirPath());
244 Wait();
245 }
246
247 // Enables recording without adding a profile.
InitWithoutLogin()248 void InitWithoutLogin() {
249 // Create a system profile, normally done by ChromeMetricsServiceClient.
250 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
251 // Create the provider, normally done by the ChromeMetricsServiceClient.
252 provider_ = std::unique_ptr<StructuredMetricsProvider>(
253 new StructuredMetricsProvider(
254 DeviceKeyFilePath(),
255 /*write_delay=*/base::Seconds(0),
256 /*min_independent_metrics_interval=*/base::Seconds(0),
257 system_profile_provider_.get()));
258 // Enable recording, normally done after the metrics service has checked
259 // consent allows recording.
260 provider_->OnRecordingEnabled();
261 }
262
is_initialized()263 bool is_initialized() {
264 return provider_->init_state_ ==
265 StructuredMetricsProvider::InitState::kInitialized;
266 }
267
is_recording_enabled()268 bool is_recording_enabled() { return provider_->recording_enabled_; }
269
OnRecordingEnabled()270 void OnRecordingEnabled() { provider_->OnRecordingEnabled(); }
271
OnRecordingDisabled()272 void OnRecordingDisabled() { provider_->OnRecordingDisabled(); }
273
OnReportingStateChanged(bool enabled)274 void OnReportingStateChanged(bool enabled) {
275 provider_->OnReportingStateChanged(enabled);
276 }
277
OnProfileAdded(const base::FilePath & path)278 void OnProfileAdded(const base::FilePath& path) {
279 provider_->OnProfileAdded(path);
280 }
281
WriteNow()282 void WriteNow() {
283 provider_->WriteNowForTest();
284 Wait();
285 }
286
GetSessionData()287 StructuredDataProto GetSessionData() {
288 ChromeUserMetricsExtension uma_proto;
289 provider_->ProvideCurrentSessionData(&uma_proto);
290 Wait();
291 return uma_proto.structured_data();
292 }
293
GetIndependentMetrics()294 StructuredDataProto GetIndependentMetrics() {
295 ChromeUserMetricsExtension uma_proto;
296 if (provider_->HasIndependentMetrics()) {
297 provider_->ProvideIndependentMetrics(
298 base::BindOnce([](bool success) { CHECK(success); }), &uma_proto,
299 nullptr);
300 Wait();
301 return uma_proto.structured_data();
302 }
303
304 auto p = StructuredDataProto();
305 return p;
306 }
307
GetUmaProto()308 ChromeUserMetricsExtension GetUmaProto() {
309 ChromeUserMetricsExtension uma_proto;
310 if (provider_->HasIndependentMetrics()) {
311 provider_->ProvideIndependentMetrics(
312 base::BindOnce([](bool success) { CHECK(success); }), &uma_proto,
313 nullptr);
314 Wait();
315 return uma_proto;
316 }
317
318 auto p = ChromeUserMetricsExtension();
319 return p;
320 }
321
ExpectNoErrors()322 void ExpectNoErrors() {
323 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError",
324 0);
325 }
326
SetExternalMetricsDirForTest(const base::FilePath dir)327 void SetExternalMetricsDirForTest(const base::FilePath dir) {
328 provider_->SetExternalMetricsDirForTest(dir);
329 }
330
InitializeSystemProfile()331 void InitializeSystemProfile() { provider_->OnSystemProfileInitialized(); }
332
333 protected:
334 std::unique_ptr<MetricsProvider> system_profile_provider_;
335 std::unique_ptr<StructuredMetricsProvider> provider_;
336 // Feature list should be constructed before task environment.
337 base::test::ScopedFeatureList scoped_feature_list_;
338 base::test::TaskEnvironment task_environment_{
339 base::test::TaskEnvironment::MainThreadType::UI,
340 base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED,
341 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
342 base::HistogramTester histogram_tester_;
343 base::ScopedTempDir temp_dir_;
344
345 private:
346 TestRecorder recorder_;
347 };
348
349 // Simple test to ensure initialization works correctly in the case of a
350 // first-time run.
TEST_F(StructuredMetricsProviderTest,ProviderInitializesFromBlankSlate)351 TEST_F(StructuredMetricsProviderTest, ProviderInitializesFromBlankSlate) {
352 Init();
353 EXPECT_TRUE(is_initialized());
354 EXPECT_TRUE(is_recording_enabled());
355 ExpectNoErrors();
356 }
357
358 // Ensure a call to OnRecordingDisabled prevents reporting.
TEST_F(StructuredMetricsProviderTest,EventsNotReportedWhenRecordingDisabled)359 TEST_F(StructuredMetricsProviderTest, EventsNotReportedWhenRecordingDisabled) {
360 Init();
361 OnRecordingDisabled();
362 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
363 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
364 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
365 EXPECT_EQ(GetSessionData().events_size(), 0);
366 ExpectNoErrors();
367 }
368
369 // Ensure that disabling the structured metrics feature flag prevents all
370 // structured metrics reporting.
TEST_F(StructuredMetricsProviderTest,EventsNotReportedWhenFeatureDisabled)371 TEST_F(StructuredMetricsProviderTest, EventsNotReportedWhenFeatureDisabled) {
372 scoped_feature_list_.InitAndDisableFeature(kStructuredMetrics);
373
374 Init();
375 // OnRecordingEnabled should not actually enable recording because the flag is
376 // disabled.
377 OnRecordingEnabled();
378 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
379 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
380 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
381 EXPECT_EQ(GetSessionData().events_size(), 0);
382 ExpectNoErrors();
383 }
384
385 // Ensure that keys and unsent logs are deleted when reporting is disabled, and
386 // that reporting resumes when re-enabled.
TEST_F(StructuredMetricsProviderTest,ReportingStateChangesHandledCorrectly)387 TEST_F(StructuredMetricsProviderTest, ReportingStateChangesHandledCorrectly) {
388 Init();
389
390 // Record an event and read the keys, there should be one.
391 events::v2::test_project_one::TestEventOne().Record();
392 EXPECT_EQ(GetIndependentMetrics().events_size(), 1);
393
394 const KeyDataProto enabled_proto = ReadKeys(ProfileKeyFilePath());
395 EXPECT_EQ(enabled_proto.keys_size(), 1);
396
397 // Record an event, disable reporting, then record another event. Both of
398 // these events should have been ignored.
399 events::v2::test_project_one::TestEventOne().Record();
400 OnReportingStateChanged(false);
401 events::v2::test_project_one::TestEventOne().Record();
402 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
403
404 // Read the keys again, it should be empty.
405 const KeyDataProto disabled_proto = ReadKeys(ProfileKeyFilePath());
406 EXPECT_EQ(disabled_proto.keys_size(), 0);
407
408 // Enable reporting again, and record an event.
409 OnReportingStateChanged(true);
410 OnRecordingEnabled();
411 events::v2::test_project_one::TestEventOne().Record();
412 EXPECT_EQ(GetIndependentMetrics().events_size(), 1);
413 const KeyDataProto reenabled_proto = ReadKeys(ProfileKeyFilePath());
414 EXPECT_EQ(reenabled_proto.keys_size(), 1);
415
416 ExpectNoErrors();
417 }
418
419 // Ensure that disabling independent upload of non-client_id metrics via feature
420 // flag instead uploads them in the main UMA upload.
TEST_F(StructuredMetricsProviderTest,DisableIndependentUploads)421 TEST_F(StructuredMetricsProviderTest, DisableIndependentUploads) {
422 scoped_feature_list_.InitAndEnableFeatureWithParameters(
423 kStructuredMetrics, {{"enable_independent_metrics_upload", "false"}});
424
425 Init();
426 OnRecordingEnabled();
427 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
428 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
429 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
430 EXPECT_EQ(GetSessionData().events_size(), 2);
431 ExpectNoErrors();
432 }
433
434 // Ensure that, if recording is disabled part-way through initialization, the
435 // initialization still completes correctly, but recording is correctly set to
436 // disabled.
TEST_F(StructuredMetricsProviderTest,RecordingDisabledDuringInitialization)437 TEST_F(StructuredMetricsProviderTest, RecordingDisabledDuringInitialization) {
438 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
439 provider_ = std::make_unique<StructuredMetricsProvider>(
440 system_profile_provider_.get());
441
442 OnProfileAdded(TempDirPath());
443 OnRecordingDisabled();
444 EXPECT_FALSE(is_initialized());
445 EXPECT_FALSE(is_recording_enabled());
446
447 Wait();
448 EXPECT_TRUE(is_initialized());
449 EXPECT_FALSE(is_recording_enabled());
450
451 ExpectNoErrors();
452 }
453
454 // Ensure that recording is disabled until explicitly enabled with a call to
455 // OnRecordingEnabled.
TEST_F(StructuredMetricsProviderTest,RecordingDisabledByDefault)456 TEST_F(StructuredMetricsProviderTest, RecordingDisabledByDefault) {
457 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
458 provider_ = std::make_unique<StructuredMetricsProvider>(
459 system_profile_provider_.get());
460
461 OnProfileAdded(TempDirPath());
462 Wait();
463 EXPECT_TRUE(is_initialized());
464 EXPECT_FALSE(is_recording_enabled());
465
466 OnRecordingEnabled();
467 EXPECT_TRUE(is_recording_enabled());
468
469 ExpectNoErrors();
470 }
471
TEST_F(StructuredMetricsProviderTest,RecordedEventAppearsInReport)472 TEST_F(StructuredMetricsProviderTest, RecordedEventAppearsInReport) {
473 Init();
474
475 events::v2::test_project_one::TestEventOne()
476 .SetTestMetricOne("a string")
477 .SetTestMetricTwo(12345)
478 .Record();
479 events::v2::test_project_one::TestEventOne()
480 .SetTestMetricOne("a string")
481 .SetTestMetricTwo(12345)
482 .Record();
483 events::v2::test_project_one::TestEventOne()
484 .SetTestMetricOne("a string")
485 .SetTestMetricTwo(12345)
486 .Record();
487
488 EXPECT_EQ(GetIndependentMetrics().events_size(), 3);
489 // TestProjectOne is not UMA ID'd, so GetSessionData should be empty.
490 EXPECT_EQ(GetSessionData().events_size(), 0);
491 ExpectNoErrors();
492 }
493
TEST_F(StructuredMetricsProviderTest,UmaEventsReportedCorrectly)494 TEST_F(StructuredMetricsProviderTest, UmaEventsReportedCorrectly) {
495 WriteTestingProfileKeys();
496 Init();
497
498 events::v2::test_project_three::TestEventFour()
499 .SetTestMetricFour(12345)
500 .Record();
501 events::v2::test_project_three::TestEventFour()
502 .SetTestMetricFour(67890)
503 .Record();
504
505 const auto data = GetSessionData();
506 ASSERT_EQ(data.events_size(), 2);
507
508 { // First event
509 const auto& event = data.events(0);
510 EXPECT_EQ(event.event_name_hash(), kEventFourHash);
511 EXPECT_EQ(event.project_name_hash(), kProjectThreeHash);
512 // TODO(crbug.com/1148168): The UMA ID currently isn't attached to UMA
513 // events, so just check it isn't set.
514 EXPECT_FALSE(event.has_profile_event_id());
515 ASSERT_EQ(event.metrics_size(), 1);
516 const auto& metric = event.metrics(0);
517 EXPECT_EQ(metric.name_hash(), kMetricFourHash);
518 EXPECT_EQ(metric.value_int64(), 12345);
519 }
520
521 { // Second event
522 const auto& event = data.events(1);
523 EXPECT_EQ(event.event_name_hash(), kEventFourHash);
524 EXPECT_EQ(event.project_name_hash(), kProjectThreeHash);
525 // TODO(crbug.com/1148168): The UMA ID currently isn't attached to UMA
526 // events, so just check it isn't set.
527 EXPECT_FALSE(event.has_profile_event_id());
528 ASSERT_EQ(event.metrics_size(), 1);
529 const auto& metric = event.metrics(0);
530 EXPECT_EQ(metric.name_hash(), kMetricFourHash);
531 EXPECT_EQ(metric.value_int64(), 67890);
532 }
533
534 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0);
535 }
536
TEST_F(StructuredMetricsProviderTest,IndependentEventsReportedCorrectly)537 TEST_F(StructuredMetricsProviderTest, IndependentEventsReportedCorrectly) {
538 WriteTestingProfileKeys();
539 Init();
540
541 events::v2::test_project_one::TestEventOne()
542 .SetTestMetricOne(kValueOne)
543 .SetTestMetricTwo(12345)
544 .Record();
545 events::v2::test_project_two::TestEventTwo()
546 .SetTestMetricThree(kValueTwo)
547 .Record();
548
549 const auto data = GetIndependentMetrics();
550 ASSERT_EQ(data.events_size(), 2);
551
552 { // First event
553 const auto& event = data.events(0);
554 EXPECT_EQ(event.event_name_hash(), kEventOneHash);
555 EXPECT_EQ(event.project_name_hash(), kProjectOneHash);
556 EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectOneId);
557 ASSERT_EQ(event.metrics_size(), 2);
558
559 { // First metric
560 const auto& metric = event.metrics(0);
561 EXPECT_EQ(metric.name_hash(), kMetricOneHash);
562 EXPECT_EQ(HashToHex(metric.value_hmac()),
563 // Value of HMAC_256("aaa...a", concat(hex(kMetricOneHash),
564 // kValueOne))
565 "8C2469269D142715");
566 }
567
568 { // Second metric
569 const auto& metric = event.metrics(1);
570 EXPECT_EQ(metric.name_hash(), kMetricTwoHash);
571 EXPECT_EQ(metric.value_int64(), 12345);
572 }
573 }
574
575 { // Second event
576 const auto& event = data.events(1);
577 EXPECT_EQ(event.event_name_hash(), kEventTwoHash);
578 EXPECT_EQ(event.project_name_hash(), kProjectTwoHash);
579 EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectTwoId);
580 ASSERT_EQ(event.metrics_size(), 1);
581
582 { // First metric
583 const auto& metric = event.metrics(0);
584 EXPECT_EQ(metric.name_hash(), kMetricThreeHash);
585 EXPECT_EQ(HashToHex(metric.value_hmac()),
586 // Value of HMAC_256("bbb...b", concat(hex(kProjectTwoHash),
587 // kValueTwo))
588 "86F0169868588DC7");
589 }
590 }
591
592 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0);
593 }
594
TEST_F(StructuredMetricsProviderTest,IndependentMetricsProvideSystemProfile)595 TEST_F(StructuredMetricsProviderTest, IndependentMetricsProvideSystemProfile) {
596 WriteTestingProfileKeys();
597 Init();
598 InitializeSystemProfile();
599
600 events::v2::test_project_one::TestEventOne()
601 .SetTestMetricOne(kValueOne)
602 .SetTestMetricTwo(12345)
603 .Record();
604 events::v2::test_project_two::TestEventTwo()
605 .SetTestMetricThree(kValueTwo)
606 .Record();
607
608 const auto uma_proto = GetUmaProto();
609 CHECK(uma_proto.has_system_profile());
610
611 {
612 const auto structured_profile = uma_proto.system_profile();
613 EXPECT_EQ(structured_profile.multi_profile_user_count(), kUserCount);
614 EXPECT_EQ(structured_profile.hardware().full_hardware_class(), kHwid);
615 }
616
617 const auto data = uma_proto.structured_data();
618 ASSERT_EQ(data.events_size(), 2);
619
620 { // First event
621 const auto& event = data.events(0);
622 EXPECT_EQ(event.event_name_hash(), kEventOneHash);
623 EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectOneId);
624 ASSERT_EQ(event.metrics_size(), 2);
625 {}
626
627 { // First metric
628 const auto& metric = event.metrics(0);
629 EXPECT_EQ(metric.name_hash(), kMetricOneHash);
630 EXPECT_EQ(HashToHex(metric.value_hmac()),
631 // Value of HMAC_256("aaa...a", concat(hex(kMetricOneHash),
632 // kValueOne))
633 "8C2469269D142715");
634 }
635
636 { // Second metric
637 const auto& metric = event.metrics(1);
638 EXPECT_EQ(metric.name_hash(), kMetricTwoHash);
639 EXPECT_EQ(metric.value_int64(), 12345);
640 }
641 }
642
643 { // Second event
644 const auto& event = data.events(1);
645 EXPECT_EQ(event.event_name_hash(), kEventTwoHash);
646 EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectTwoId);
647 ASSERT_EQ(event.metrics_size(), 1);
648
649 { // First metric
650 const auto& metric = event.metrics(0);
651 EXPECT_EQ(metric.name_hash(), kMetricThreeHash);
652 EXPECT_EQ(HashToHex(metric.value_hmac()),
653 // Value of HMAC_256("bbb...b", concat(hex(kProjectTwoHash),
654 // kValueTwo))
655 "86F0169868588DC7");
656 }
657 }
658
659 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0);
660 }
661
662 // Ensure that events containing raw string metrics are reported correctly.
TEST_F(StructuredMetricsProviderTest,RawStringMetricsReportedCorrectly)663 TEST_F(StructuredMetricsProviderTest, RawStringMetricsReportedCorrectly) {
664 Init();
665
666 const std::string test_string = "a raw string value";
667 events::v2::test_project_five::TestEventSix()
668 .SetTestMetricSix(test_string)
669 .Record();
670
671 const auto data = GetIndependentMetrics();
672 ASSERT_EQ(data.events_size(), 1);
673
674 const auto& event = data.events(0);
675 EXPECT_EQ(event.event_name_hash(), kEventSixHash);
676 EXPECT_EQ(event.project_name_hash(), kProjectFiveHash);
677 EXPECT_FALSE(event.has_profile_event_id());
678 EXPECT_EQ(event.event_type(), StructuredEventProto_EventType_RAW_STRING);
679
680 ASSERT_EQ(event.metrics_size(), 1);
681 const auto& metric = event.metrics(0);
682
683 EXPECT_EQ(metric.name_hash(), kMetricSixHash);
684 EXPECT_EQ(metric.value_string(), test_string);
685 }
686
TEST_F(StructuredMetricsProviderTest,FloatMetricsReportedCorrectly)687 TEST_F(StructuredMetricsProviderTest, FloatMetricsReportedCorrectly) {
688 Init();
689
690 const float test_float = 3.4;
691 const float test_float2 = 3.14e-8;
692
693 events::v2::test_project_six::TestEventSeven()
694 .SetTestMetricSeven(test_float)
695 .Record();
696
697 events::v2::test_project_six::TestEventSeven()
698 .SetTestMetricSeven(test_float2)
699 .Record();
700
701 const auto data = GetIndependentMetrics();
702 ASSERT_EQ(data.events_size(), 2);
703
704 const auto& event = data.events(0);
705 EXPECT_EQ(event.event_name_hash(), kEventSevenHash);
706 EXPECT_EQ(event.project_name_hash(), kProjectSixHash);
707 EXPECT_FALSE(event.has_profile_event_id());
708
709 ASSERT_EQ(event.metrics_size(), 1);
710 const auto& metric = event.metrics(0);
711
712 EXPECT_EQ(metric.name_hash(), kMetricSevenHash);
713 EXPECT_EQ(metric.value_double(), test_float);
714
715 const auto& event2 = data.events(1);
716 EXPECT_EQ(event2.event_name_hash(), kEventSevenHash);
717 EXPECT_EQ(event2.project_name_hash(), kProjectSixHash);
718 EXPECT_FALSE(event2.has_profile_event_id());
719
720 ASSERT_EQ(event2.metrics_size(), 1);
721 const auto& metric2 = event2.metrics(0);
722
723 EXPECT_EQ(metric2.name_hash(), kMetricSevenHash);
724 EXPECT_EQ(metric2.value_double(), test_float2);
725 }
726
TEST_F(StructuredMetricsProviderTest,DeviceKeysUsedForDeviceScopedProjects)727 TEST_F(StructuredMetricsProviderTest, DeviceKeysUsedForDeviceScopedProjects) {
728 WriteTestingProfileKeys();
729 WriteTestingDeviceKeys();
730 Init();
731
732 // This event's project has device scope set, so should use the per-device
733 // keys set by WriteTestingDeviceKeys. In this case the expected key is
734 // "ddd...d", which we observe by checking the ID and HMAC have the correct
735 // value given that key.
736 events::v2::test_project_four::TestEventFive()
737 .SetTestMetricFive("value")
738 .Record();
739
740 const auto data = GetIndependentMetrics();
741 ASSERT_EQ(data.events_size(), 1);
742
743 const auto& event = data.events(0);
744 EXPECT_EQ(event.event_name_hash(), kEventFiveHash);
745 EXPECT_EQ(event.project_name_hash(), kProjectFourHash);
746 // The hex-encoded first 8 bytes of SHA256("ddd...d").
747 EXPECT_EQ(HashToHex(event.profile_event_id()), kProjectFourId);
748 ASSERT_EQ(event.metrics_size(), 1);
749
750 const auto& metric = event.metrics(0);
751 EXPECT_EQ(metric.name_hash(), kMetricFiveHash);
752 EXPECT_EQ(HashToHex(metric.value_hmac()),
753 // Value of HMAC_256("ddd...d", concat(hex(kMetricFiveHash),
754 // "value"))
755 "4CC202FAA78FDC7A");
756
757 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0);
758 }
759
760 // Check that a full int64 can be recorded, and is not truncated to an int32.
TEST_F(StructuredMetricsProviderTest,Int64MetricsNotTruncated)761 TEST_F(StructuredMetricsProviderTest, Int64MetricsNotTruncated) {
762 Init();
763 const int64_t big = 1ll << 60;
764 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(big).Record();
765
766 const auto data = GetIndependentMetrics();
767 ASSERT_EQ(data.events_size(), 1);
768 const auto& event = data.events(0);
769 ASSERT_EQ(event.metrics_size(), 1);
770 const auto& metric = event.metrics(0);
771 EXPECT_EQ(metric.value_int64(), big);
772 }
773
TEST_F(StructuredMetricsProviderTest,EventsWithinProjectReportedWithSameID)774 TEST_F(StructuredMetricsProviderTest, EventsWithinProjectReportedWithSameID) {
775 WriteTestingProfileKeys();
776 Init();
777
778 events::v2::test_project_one::TestEventOne().Record();
779 events::v2::test_project_two::TestEventTwo().Record();
780 events::v2::test_project_two::TestEventThree().Record();
781
782 const auto data = GetIndependentMetrics();
783 // TestProjectOne is not UMA ID'd, so GetSessionData should be empty.
784 EXPECT_EQ(GetSessionData().events_size(), 0);
785 ASSERT_EQ(data.events_size(), 3);
786
787 const auto& event_one = data.events(0);
788 const auto& event_two = data.events(1);
789 const auto& event_three = data.events(2);
790
791 // Check events are in the right order.
792 EXPECT_EQ(event_one.event_name_hash(), kEventOneHash);
793 EXPECT_EQ(event_two.event_name_hash(), kEventTwoHash);
794 EXPECT_EQ(event_three.event_name_hash(), kEventThreeHash);
795
796 // Events two and three share a project, so should have the same project
797 // name hash. Event one should have its own project name hash.
798 EXPECT_EQ(event_one.project_name_hash(), kProjectOneHash);
799 EXPECT_EQ(event_two.project_name_hash(), kProjectTwoHash);
800 EXPECT_EQ(event_three.project_name_hash(), kProjectTwoHash);
801
802 // Events two and three share a project, so should have the same ID. Event
803 // one should have its own ID.
804 EXPECT_EQ(HashToHex(event_one.profile_event_id()), kProjectOneId);
805 EXPECT_EQ(HashToHex(event_two.profile_event_id()), kProjectTwoId);
806 EXPECT_EQ(HashToHex(event_three.profile_event_id()), kProjectTwoId);
807
808 histogram_tester_.ExpectTotalCount("UMA.StructuredMetrics.InternalError", 0);
809 }
810
TEST_F(StructuredMetricsProviderTest,EventWithoutMetricsReportCorrectly)811 TEST_F(StructuredMetricsProviderTest, EventWithoutMetricsReportCorrectly) {
812 Init();
813
814 const int test_time = 50;
815
816 events::v2::cr_os_events::NoMetricsEvent test_event;
817 EXPECT_TRUE(test_event.IsEventSequenceType());
818 test_event.SetEventSequenceMetadata(Event::EventSequenceMetadata(1));
819 test_event.SetRecordedTimeSinceBoot(base::Milliseconds(test_time));
820 test_event.Record();
821
822 const auto data = GetIndependentMetrics();
823
824 EXPECT_EQ(data.events_size(), 1);
825
826 const auto& event = data.events(0);
827
828 EXPECT_EQ(event.project_name_hash(), kCrOSEventsProjectHash);
829 EXPECT_EQ(event.event_name_hash(), kNoMetricsEventHash);
830 }
831
832 // Test that a call to ProvideCurrentSessionData clears the provided events from
833 // the cache, and a subsequent call does not return those events again.
TEST_F(StructuredMetricsProviderTest,EventsClearedAfterReport)834 TEST_F(StructuredMetricsProviderTest, EventsClearedAfterReport) {
835 Init();
836
837 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
838 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(2).Record();
839 // TestProjectOne is not UMA ID'd, so GetSessionData should be empty.
840 EXPECT_EQ(GetSessionData().events_size(), 0);
841 // Should provide both the previous events.
842 EXPECT_EQ(GetIndependentMetrics().events_size(), 2);
843
844 // But the previous events shouldn't appear in the second report.
845 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
846
847 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(3).Record();
848 // The third request should only contain the third event.
849 EXPECT_EQ(GetIndependentMetrics().events_size(), 1);
850
851 ExpectNoErrors();
852 }
853
854 // Test that events recorded in one session are correctly persisted and are
855 // uploaded in the first report from a subsequent session.
TEST_F(StructuredMetricsProviderTest,EventsFromPreviousSessionAreReported)856 TEST_F(StructuredMetricsProviderTest, EventsFromPreviousSessionAreReported) {
857 // Start first session and record one event.
858 Init();
859 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1234).Record();
860
861 // Write events to disk, then destroy the provider.
862 WriteNow();
863 provider_.reset();
864
865 // Start a second session and ensure the event is reported.
866 Init();
867 const auto data = GetIndependentMetrics();
868 ASSERT_EQ(data.events_size(), 1);
869 ASSERT_EQ(data.events(0).metrics_size(), 1);
870 EXPECT_EQ(data.events(0).metrics(0).value_int64(), 1234);
871 EXPECT_EQ(GetSessionData().events_size(), 0);
872
873 ExpectNoErrors();
874 }
875
TEST_F(StructuredMetricsProviderTest,ExternalMetricsAreReported)876 TEST_F(StructuredMetricsProviderTest, ExternalMetricsAreReported) {
877 const base::FilePath events_dir(TempDirPath().Append("events"));
878 base::CreateDirectory(events_dir);
879
880 const auto proto = MakeExternalEventProto({111, 222, 333});
881 ASSERT_TRUE(
882 base::WriteFile(events_dir.Append("event"), proto.SerializeAsString()));
883
884 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
885 provider_ = std::make_unique<StructuredMetricsProvider>(
886 system_profile_provider_.get());
887 OnProfileAdded(TempDirPath());
888 OnRecordingEnabled();
889 SetExternalMetricsDirForTest(events_dir);
890 task_environment_.AdvanceClock(base::Hours(10));
891 Wait();
892 EXPECT_EQ(GetSessionData().events_size(), 3);
893 }
894
TEST_F(StructuredMetricsProviderTest,ExternalMetricsDroppedWhenRecordingDisabled)895 TEST_F(StructuredMetricsProviderTest,
896 ExternalMetricsDroppedWhenRecordingDisabled) {
897 const base::FilePath events_dir(TempDirPath().Append("events"));
898 base::CreateDirectory(events_dir);
899
900 const auto proto = MakeExternalEventProto({111, 222, 333});
901 ASSERT_TRUE(
902 base::WriteFile(events_dir.Append("event"), proto.SerializeAsString()));
903
904 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
905 provider_ = std::make_unique<StructuredMetricsProvider>(
906 system_profile_provider_.get());
907 OnProfileAdded(TempDirPath());
908 OnRecordingDisabled();
909 SetExternalMetricsDirForTest(events_dir);
910 task_environment_.AdvanceClock(base::Hours(10));
911 Wait();
912 EXPECT_EQ(GetSessionData().events_size(), 0);
913 }
914
915 // Test that events reported before recording is enabled are ignored.
TEST_F(StructuredMetricsProviderTest,EventsNotRecordedBeforeRecordingEnabled)916 TEST_F(StructuredMetricsProviderTest, EventsNotRecordedBeforeRecordingEnabled) {
917 // Manually create and initialize the provider, adding recording calls between
918 // each step. All of these events should be ignored.
919 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
920 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
921 provider_ = std::make_unique<StructuredMetricsProvider>(
922 system_profile_provider_.get());
923 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
924 OnRecordingEnabled();
925 Wait();
926
927 EXPECT_EQ(GetSessionData().events_size(), 0);
928 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
929
930 ExpectNoErrors();
931 }
932
933 // Test that events reported after recording is enabled but before the keys are
934 // loaded are hashed and stored after keys are loaded.
TEST_F(StructuredMetricsProviderTest,EventsRecordedBeforeKeysInitialized)935 TEST_F(StructuredMetricsProviderTest, EventsRecordedBeforeKeysInitialized) {
936 InitWithoutLogin();
937 // Emulate metric before login.
938 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
939
940 OnProfileAdded(TempDirPath());
941 // Called before user key is loaded.
942 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
943 Wait();
944
945 EXPECT_EQ(GetSessionData().events_size(), 0);
946 EXPECT_EQ(GetIndependentMetrics().events_size(), 2);
947
948 ExpectNoErrors();
949 }
950
951 // Ensure a call to OnRecordingDisabled not only prevents the reporting of new
952 // events, but also clears the cache of any existing events that haven't yet
953 // been reported.
TEST_F(StructuredMetricsProviderTest,ExistingEventsClearedWhenRecordingDisabled)954 TEST_F(StructuredMetricsProviderTest,
955 ExistingEventsClearedWhenRecordingDisabled) {
956 Init();
957 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
958 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
959 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
960 OnRecordingDisabled();
961 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
962 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
963 EXPECT_EQ(GetSessionData().events_size(), 0);
964 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
965
966 ExpectNoErrors();
967 }
968
969 // Ensure that recording and reporting is re-enabled after recording is disabled
970 // and then enabled again.
TEST_F(StructuredMetricsProviderTest,ReportingResumesWhenEnabled)971 TEST_F(StructuredMetricsProviderTest, ReportingResumesWhenEnabled) {
972 Init();
973 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
974 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
975 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
976
977 OnRecordingDisabled();
978 OnRecordingEnabled();
979
980 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
981 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
982 events::v2::test_project_three::TestEventFour().SetTestMetricFour(1).Record();
983
984 EXPECT_EQ(GetSessionData().events_size(), 2);
985 EXPECT_EQ(GetIndependentMetrics().events_size(), 4);
986
987 ExpectNoErrors();
988 }
989
990 // Ensure that a call to ProvideCurrentSessionData before initialization
991 // completes returns no events.
TEST_F(StructuredMetricsProviderTest,ReportsNothingBeforeInitializationComplete)992 TEST_F(StructuredMetricsProviderTest,
993 ReportsNothingBeforeInitializationComplete) {
994 system_profile_provider_ = std::make_unique<TestSystemProfileProvider>();
995 provider_ = std::make_unique<StructuredMetricsProvider>(
996 system_profile_provider_.get());
997 EXPECT_EQ(GetSessionData().events_size(), 0);
998 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
999 OnRecordingEnabled();
1000 EXPECT_EQ(GetSessionData().events_size(), 0);
1001 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
1002 OnProfileAdded(TempDirPath());
1003 EXPECT_EQ(GetSessionData().events_size(), 0);
1004 EXPECT_EQ(GetIndependentMetrics().events_size(), 0);
1005 }
1006
1007 // Check that LastKeyRotation returns a value in the correct range of possible
1008 // last rotations for a newly generated key.
TEST_F(StructuredMetricsProviderTest,LastKeyRotation)1009 TEST_F(StructuredMetricsProviderTest, LastKeyRotation) {
1010 Init();
1011
1012 events::v2::test_project_one::TestEventOne event;
1013
1014 // Record a metric so that the key is created.
1015 event.Record();
1016
1017 const int today = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
1018 const absl::optional<int> last_rotation =
1019 Recorder::GetInstance()->LastKeyRotation(event);
1020
1021 // The last rotation should be a random day between today and 90 days in the
1022 // past, ie. the rotation period for this project.
1023 ASSERT_TRUE(last_rotation.has_value());
1024 EXPECT_GE(last_rotation, today - 90);
1025 }
1026
1027 // Ensures that events part of event sequence are recorded properly.
TEST_F(StructuredMetricsProviderTest,EventSequenceLogging)1028 TEST_F(StructuredMetricsProviderTest, EventSequenceLogging) {
1029 Init();
1030
1031 scoped_feature_list_.InitAndEnableFeature(
1032 metrics::structured::kEventSequenceLogging);
1033
1034 const int test_time = 50;
1035 const double test_metric = 1.0;
1036
1037 events::v2::cr_os_events::Test1 test_event;
1038 EXPECT_TRUE(test_event.IsEventSequenceType());
1039 test_event.SetEventSequenceMetadata(Event::EventSequenceMetadata(1));
1040 test_event.SetRecordedTimeSinceBoot(base::Milliseconds(test_time));
1041 test_event.SetMetric1(test_metric).Record();
1042
1043 const auto data = GetIndependentMetrics();
1044 ASSERT_EQ(data.events_size(), 1);
1045
1046 const auto& event = data.events(0);
1047 EXPECT_EQ(event.project_name_hash(), kCrOSEventsProjectHash);
1048
1049 // Sequence events should have both a device and user project id.
1050 EXPECT_TRUE(event.has_device_project_id());
1051 EXPECT_TRUE(event.has_user_project_id());
1052
1053 // Verify that event sequence metadata has been serialized correctly.
1054 const auto& event_metadata = event.event_sequence_metadata();
1055 EXPECT_EQ(event_metadata.reset_counter(), 1);
1056 EXPECT_TRUE(event_metadata.has_event_unique_id());
1057 EXPECT_EQ(event_metadata.system_uptime(), test_time);
1058
1059 ASSERT_EQ(event.metrics_size(), 1);
1060 const auto& metric = event.metrics(0);
1061 EXPECT_EQ(metric.value_double(), 1.0);
1062
1063 ExpectNoErrors();
1064 }
1065
TEST_F(StructuredMetricsProviderTest,EventsClone)1066 TEST_F(StructuredMetricsProviderTest, EventsClone) {
1067 Init();
1068
1069 events::v2::cr_os_events::Test1 event;
1070
1071 const int test_time = 50;
1072 const double test_metric = 1.0;
1073
1074 event.SetEventSequenceMetadata(Event::EventSequenceMetadata(1));
1075 event.SetRecordedTimeSinceBoot(base::Milliseconds(test_time));
1076 event.SetMetric1(test_metric);
1077
1078 auto cloned_event = event.Clone();
1079
1080 EXPECT_EQ(event.event_sequence_metadata().reset_counter,
1081 cloned_event.event_sequence_metadata().reset_counter);
1082 EXPECT_EQ(event.project_name(), cloned_event.project_name());
1083 EXPECT_EQ(event.event_name(), cloned_event.event_name());
1084 EXPECT_EQ(event.is_event_sequence(), cloned_event.is_event_sequence());
1085 EXPECT_EQ(event.recorded_time_since_boot(),
1086 cloned_event.recorded_time_since_boot());
1087 EXPECT_EQ(event.metric_values(), cloned_event.metric_values());
1088 }
1089
TEST_F(StructuredMetricsProviderTest,DisallowedProjectAreDropped)1090 TEST_F(StructuredMetricsProviderTest, DisallowedProjectAreDropped) {
1091 Init();
1092
1093 AddDisallowedProject(kProjectOneHash);
1094
1095 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
1096 events::v2::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
1097 events::v2::test_project_two::TestEventThree()
1098 .SetTestMetricFour("value")
1099 .Record();
1100
1101 const auto data = GetIndependentMetrics();
1102 ASSERT_EQ(data.events_size(), 1);
1103 ASSERT_EQ(data.events(0).project_name_hash(), kProjectTwoHash);
1104 }
1105
1106 } // namespace metrics::structured
1107