1 // Copyright 2016 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.
5 #include "components/metrics/file_metrics_provider.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/memory_mapped_file.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/histogram_base.h"
18 #include "base/metrics/histogram_flattener.h"
19 #include "base/metrics/histogram_snapshot_manager.h"
20 #include "base/metrics/persistent_histogram_allocator.h"
21 #include "base/metrics/persistent_memory_allocator.h"
22 #include "base/metrics/sparse_histogram.h"
23 #include "base/metrics/statistics_recorder.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/synchronization/waitable_event.h"
26 #include "base/test/bind.h"
27 #include "base/test/metrics/histogram_tester.h"
28 #include "base/test/task_environment.h"
29 #include "base/time/time.h"
30 #include "components/metrics/metrics_log.h"
31 #include "components/metrics/metrics_pref_names.h"
32 #include "components/metrics/persistent_system_profile.h"
33 #include "components/prefs/pref_registry_simple.h"
34 #include "components/prefs/testing_pref_service.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
38 #include "third_party/metrics_proto/system_profile.pb.h"
41 const char kMetricsName[] = "TestMetrics";
42 const char kMergedCountHistogramName[] =
43 "UMA.FileMetricsProvider.TestMetrics.MergedHistogramsCount";
44 const char kMetricsFilename[] = "file.metrics";
46 void WriteSystemProfileToAllocator(
47 base::PersistentHistogramAllocator* allocator) {
48 metrics::SystemProfileProto profile_proto;
49 // Add a field trial to verify that FileMetricsProvider will produce an
50 // independent log with the written system profile.
51 metrics::SystemProfileProto::FieldTrial* trial =
52 profile_proto.add_field_trial();
53 trial->set_name_id(123);
54 trial->set_group_id(456);
55 metrics::PersistentSystemProfile persistent_profile;
56 persistent_profile.RegisterPersistentAllocator(allocator->memory_allocator());
57 persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
63 class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
65 HistogramFlattenerDeltaRecorder() = default;
67 HistogramFlattenerDeltaRecorder(const HistogramFlattenerDeltaRecorder&) =
69 HistogramFlattenerDeltaRecorder& operator=(
70 const HistogramFlattenerDeltaRecorder&) = delete;
72 void RecordDelta(const base::HistogramBase& histogram,
73 const base::HistogramSamples& snapshot) override {
74 // Only remember locally created histograms; they have exactly 2 chars.
75 if (strlen(histogram.histogram_name()) == 2)
76 recorded_delta_histogram_names_.push_back(histogram.histogram_name());
79 std::vector<std::string> GetRecordedDeltaHistogramNames() {
80 return recorded_delta_histogram_names_;
84 std::vector<std::string> recorded_delta_histogram_names_;
87 // Exactly the same as FileMetricsProvider, but provides a way to "hook" into
88 // RecordSourcesChecked() and run a callback each time it is called so that it
89 // is easier to individually verify the sources being merged.
90 class TestFileMetricsProvider : public FileMetricsProvider {
92 using FileMetricsProvider::FileMetricsProvider;
94 TestFileMetricsProvider(const TestFileMetricsProvider&) = delete;
95 TestFileMetricsProvider& operator=(const TestFileMetricsProvider&) = delete;
97 ~TestFileMetricsProvider() override = default;
99 // Sets the callback to run after RecordSourcesChecked() is called. Used to
100 // individually verify the sources being merged.
101 void SetSourcesCheckedCallback(base::RepeatingClosure callback) {
102 callback_ = std::move(callback);
106 // FileMetricsProvider:
107 void RecordSourcesChecked(SourceInfoList* checked,
108 std::vector<size_t> samples_counts) override {
109 if (!callback_.is_null()) {
113 FileMetricsProvider::RecordSourcesChecked(checked, samples_counts);
116 // A callback to run after a call to RecordSourcesChecked().
117 base::RepeatingClosure callback_;
120 class FileMetricsProviderTest : public testing::TestWithParam<bool> {
122 FileMetricsProviderTest(const FileMetricsProviderTest&) = delete;
123 FileMetricsProviderTest& operator=(const FileMetricsProviderTest&) = delete;
126 const size_t kSmallFileSize = 64 << 10; // 64 KiB
127 const size_t kLargeFileSize = 2 << 20; // 2 MiB
129 enum : int { kMaxCreateHistograms = 10 };
131 FileMetricsProviderTest()
132 : create_large_files_(GetParam()),
133 statistics_recorder_(
134 base::StatisticsRecorder::CreateTemporaryForTesting()),
135 prefs_(new TestingPrefServiceSimple) {
136 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
137 FileMetricsProvider::RegisterSourcePrefs(prefs_->registry(), kMetricsName);
140 ~FileMetricsProviderTest() override {
141 // Clear out any final remaining tasks.
142 task_environment_.RunUntilIdle();
143 DCHECK_EQ(0U, filter_actions_remaining_);
144 // If a global histogram allocator exists at this point then it likely
145 // acquired histograms that will continue to point to the released
146 // memory and potentially cause use-after-free memory corruption.
147 DCHECK(!base::GlobalHistogramAllocator::Get());
150 base::test::TaskEnvironment* task_environment() { return &task_environment_; }
151 TestingPrefServiceSimple* prefs() { return prefs_.get(); }
152 base::FilePath temp_dir() { return temp_dir_.GetPath(); }
153 base::FilePath metrics_file() {
154 return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
157 TestFileMetricsProvider* provider() {
159 provider_ = std::make_unique<TestFileMetricsProvider>(prefs());
160 return provider_.get();
163 void OnDidCreateMetricsLog() {
164 provider()->OnDidCreateMetricsLog();
167 bool HasPreviousSessionData() { return provider()->HasPreviousSessionData(); }
169 void MergeHistogramDeltas() {
170 provider()->MergeHistogramDeltas(/*async=*/false,
171 /*done_callback=*/base::DoNothing());
174 bool HasIndependentMetrics() { return provider()->HasIndependentMetrics(); }
176 bool ProvideIndependentMetrics(
177 ChromeUserMetricsExtension* uma_proto,
178 base::HistogramSnapshotManager* snapshot_manager) {
179 bool success = false;
180 bool success_set = false;
181 provider()->ProvideIndependentMetrics(
184 [](bool* success_ptr, bool* set_ptr, bool s) {
188 &success, &success_set),
189 uma_proto, snapshot_manager);
191 task_environment()->RunUntilIdle();
196 void RecordInitialHistogramSnapshots(
197 base::HistogramSnapshotManager* snapshot_manager) {
198 provider()->RecordInitialHistogramSnapshots(snapshot_manager);
201 size_t GetSnapshotHistogramCount() {
202 // Merge the data from the allocator into the StatisticsRecorder.
203 MergeHistogramDeltas();
205 // Flatten what is known to see what has changed since the last time.
206 HistogramFlattenerDeltaRecorder flattener;
207 base::HistogramSnapshotManager snapshot_manager(&flattener);
208 // "true" to the begin() includes histograms held in persistent storage.
209 base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
210 base::Histogram::kNoFlags,
212 return flattener.GetRecordedDeltaHistogramNames().size();
215 size_t GetIndependentHistogramCount() {
216 HistogramFlattenerDeltaRecorder flattener;
217 base::HistogramSnapshotManager snapshot_manager(&flattener);
218 ChromeUserMetricsExtension uma_proto;
219 provider()->ProvideIndependentMetrics(base::DoNothing(),
220 base::BindOnce([](bool success) {}),
221 &uma_proto, &snapshot_manager);
223 task_environment()->RunUntilIdle();
224 return flattener.GetRecordedDeltaHistogramNames().size();
227 void CreateGlobalHistograms(int histogram_count) {
228 DCHECK_GT(kMaxCreateHistograms, histogram_count);
230 // Create both sparse and normal histograms in the allocator. Make them
231 // stability histograms to ensure that the histograms are snapshotted (in
232 // the case of stability logs) or are put into independent logs. Histogram
233 // names must be 2 characters (see HistogramFlattenerDeltaRecorder).
234 created_histograms_[0] = base::SparseHistogram::FactoryGet(
235 "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
236 created_histograms_[0]->Add(0);
237 for (int i = 1; i < histogram_count; ++i) {
238 created_histograms_[i] = base::Histogram::FactoryGet(
239 base::StringPrintf("h%d", i), 1, 100, 10,
240 /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
241 created_histograms_[i]->Add(i);
245 void WriteMetricsFile(const base::FilePath& path,
246 base::PersistentHistogramAllocator* metrics) {
247 base::File writer(path,
248 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
249 // Use DCHECK so the stack-trace will indicate where this was called.
250 DCHECK(writer.IsValid()) << path;
251 size_t file_size = create_large_files_ ? metrics->size() : metrics->used();
252 int written = writer.Write(0, (const char*)metrics->data(), file_size);
253 DCHECK_EQ(static_cast<int>(file_size), written);
256 void WriteMetricsFileAtTime(const base::FilePath& path,
257 base::PersistentHistogramAllocator* metrics,
258 base::Time write_time) {
259 WriteMetricsFile(path, metrics);
260 base::TouchFile(path, write_time, write_time);
263 base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
264 const base::FilePath& file_path,
265 base::Time write_time,
267 base::OnceCallback<void(base::PersistentHistogramAllocator*)> callback) {
268 base::GlobalHistogramAllocator::CreateWithLocalMemory(
269 create_large_files_ ? kLargeFileSize : kSmallFileSize,
272 CreateGlobalHistograms(histogram_count);
274 base::GlobalHistogramAllocator* histogram_allocator =
275 base::GlobalHistogramAllocator::ReleaseForTesting();
276 std::move(callback).Run(histogram_allocator);
278 WriteMetricsFileAtTime(file_path, histogram_allocator, write_time);
279 return histogram_allocator;
282 base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
283 int histogram_count) {
284 return CreateMetricsFileWithHistograms(
285 metrics_file(), base::Time::Now(), histogram_count,
286 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {}));
289 base::HistogramBase* GetCreatedHistogram(int index) {
290 DCHECK_GT(kMaxCreateHistograms, index);
291 return created_histograms_[index];
294 void SetFilterActions(FileMetricsProvider::Params* params,
295 const FileMetricsProvider::FilterAction* actions,
297 filter_actions_ = actions;
298 filter_actions_remaining_ = count;
299 params->filter = base::BindRepeating(
300 &FileMetricsProviderTest::FilterSourcePath, base::Unretained(this));
303 const bool create_large_files_;
306 FileMetricsProvider::FilterAction FilterSourcePath(
307 const base::FilePath& path) {
308 DCHECK_LT(0U, filter_actions_remaining_);
309 --filter_actions_remaining_;
310 return *filter_actions_++;
313 base::test::TaskEnvironment task_environment_;
314 std::unique_ptr<base::StatisticsRecorder> statistics_recorder_;
315 base::ScopedTempDir temp_dir_;
316 std::unique_ptr<TestingPrefServiceSimple> prefs_;
317 std::unique_ptr<TestFileMetricsProvider> provider_;
318 base::HistogramBase* created_histograms_[kMaxCreateHistograms];
320 raw_ptr<const FileMetricsProvider::FilterAction, AllowPtrArithmetic>
321 filter_actions_ = nullptr;
322 size_t filter_actions_remaining_ = 0;
325 // Run all test cases with both small and large files.
326 INSTANTIATE_TEST_SUITE_P(SmallAndLargeFiles,
327 FileMetricsProviderTest,
330 TEST_P(FileMetricsProviderTest, AccessMetrics) {
331 ASSERT_FALSE(PathExists(metrics_file()));
332 base::HistogramTester histogram_tester;
334 base::Time metrics_time = base::Time::Now() - base::Minutes(5);
335 base::GlobalHistogramAllocator* histogram_allocator =
336 CreateMetricsFileWithHistograms(2);
337 ASSERT_TRUE(PathExists(metrics_file()));
338 base::TouchFile(metrics_file(), metrics_time, metrics_time);
340 // Register the file and allow the "checker" task to run.
341 provider()->RegisterSource(FileMetricsProvider::Params(
342 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
343 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
344 histogram_tester.ExpectTotalCount(kMergedCountHistogramName,
345 /*expected_count=*/0);
347 // Record embedded snapshots via snapshot-manager.
348 OnDidCreateMetricsLog();
349 task_environment()->RunUntilIdle();
350 EXPECT_EQ(2U, GetSnapshotHistogramCount());
351 histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
352 /*expected_bucket_count=*/1);
353 EXPECT_FALSE(base::PathExists(metrics_file()));
355 // Make sure a second call to the snapshot-recorder doesn't break anything.
356 OnDidCreateMetricsLog();
357 task_environment()->RunUntilIdle();
358 EXPECT_EQ(0U, GetSnapshotHistogramCount());
360 // File should have been deleted but recreate it to test behavior should
361 // the file not be deletable by this process.
362 WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
364 // Second full run on the same file should produce nothing.
365 OnDidCreateMetricsLog();
366 task_environment()->RunUntilIdle();
367 EXPECT_EQ(0U, GetSnapshotHistogramCount());
368 histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
369 /*expected_bucket_count=*/1);
370 EXPECT_FALSE(base::PathExists(metrics_file()));
372 // Recreate the file to indicate that it is "new" and must be recorded.
373 metrics_time = metrics_time + base::Minutes(1);
374 WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
376 // This run should again have "new" histograms.
377 OnDidCreateMetricsLog();
378 task_environment()->RunUntilIdle();
379 EXPECT_EQ(2U, GetSnapshotHistogramCount());
380 histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
381 /*expected_bucket_count=*/2);
382 EXPECT_FALSE(base::PathExists(metrics_file()));
385 TEST_P(FileMetricsProviderTest, AccessTimeLimitedFile) {
386 ASSERT_FALSE(PathExists(metrics_file()));
388 base::Time metrics_time = base::Time::Now() - base::Hours(5);
389 CreateMetricsFileWithHistograms(2);
390 ASSERT_TRUE(PathExists(metrics_file()));
391 base::TouchFile(metrics_file(), metrics_time, metrics_time);
393 // Register the file and allow the "checker" task to run.
394 FileMetricsProvider::Params params(
395 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
396 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
397 params.max_age = base::Hours(1);
398 provider()->RegisterSource(params);
400 // Attempt to access the file should return nothing.
401 OnDidCreateMetricsLog();
402 task_environment()->RunUntilIdle();
403 EXPECT_EQ(0U, GetSnapshotHistogramCount());
404 EXPECT_FALSE(base::PathExists(metrics_file()));
407 TEST_P(FileMetricsProviderTest, FilterDelaysFile) {
408 ASSERT_FALSE(PathExists(metrics_file()));
410 base::Time now_time = base::Time::Now();
411 base::Time metrics_time = now_time - base::Minutes(5);
412 CreateMetricsFileWithHistograms(2);
413 ASSERT_TRUE(PathExists(metrics_file()));
414 base::TouchFile(metrics_file(), metrics_time, metrics_time);
415 base::File::Info fileinfo;
416 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
417 EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
419 // Register the file and allow the "checker" task to run.
420 FileMetricsProvider::Params params(
421 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
422 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
423 const FileMetricsProvider::FilterAction actions[] = {
424 FileMetricsProvider::FILTER_TRY_LATER,
425 FileMetricsProvider::FILTER_PROCESS_FILE};
426 SetFilterActions(¶ms, actions, std::size(actions));
427 provider()->RegisterSource(params);
429 // Processing the file should touch it but yield no results. File timestamp
430 // accuracy is limited so compare the touched time to a couple seconds past.
431 OnDidCreateMetricsLog();
432 task_environment()->RunUntilIdle();
433 EXPECT_EQ(0U, GetSnapshotHistogramCount());
434 EXPECT_TRUE(base::PathExists(metrics_file()));
435 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
436 EXPECT_LT(metrics_time, fileinfo.last_modified);
437 EXPECT_LE(now_time - base::Seconds(2), fileinfo.last_modified);
439 // Second full run on the same file should process the file.
440 OnDidCreateMetricsLog();
441 task_environment()->RunUntilIdle();
442 EXPECT_EQ(2U, GetSnapshotHistogramCount());
443 EXPECT_FALSE(base::PathExists(metrics_file()));
446 TEST_P(FileMetricsProviderTest, FilterSkipsFile) {
447 ASSERT_FALSE(PathExists(metrics_file()));
449 base::Time now_time = base::Time::Now();
450 base::Time metrics_time = now_time - base::Minutes(5);
451 CreateMetricsFileWithHistograms(2);
452 ASSERT_TRUE(PathExists(metrics_file()));
453 base::TouchFile(metrics_file(), metrics_time, metrics_time);
454 base::File::Info fileinfo;
455 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
456 EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
458 // Register the file and allow the "checker" task to run.
459 FileMetricsProvider::Params params(
460 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
461 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
462 const FileMetricsProvider::FilterAction actions[] = {
463 FileMetricsProvider::FILTER_SKIP_FILE};
464 SetFilterActions(¶ms, actions, std::size(actions));
465 provider()->RegisterSource(params);
467 // Processing the file should delete it.
468 OnDidCreateMetricsLog();
469 task_environment()->RunUntilIdle();
470 EXPECT_EQ(0U, GetSnapshotHistogramCount());
471 EXPECT_FALSE(base::PathExists(metrics_file()));
474 TEST_P(FileMetricsProviderTest, AccessDirectory) {
475 ASSERT_FALSE(PathExists(metrics_file()));
477 base::GlobalHistogramAllocator::CreateWithLocalMemory(
478 64 << 10, 0, kMetricsName);
479 base::GlobalHistogramAllocator* allocator =
480 base::GlobalHistogramAllocator::Get();
481 base::HistogramBase* histogram;
483 // Create files starting with a timestamp a few minutes back.
484 base::Time base_time = base::Time::Now() - base::Minutes(10);
486 // Create some files in an odd order. The files are "touched" back in time to
487 // ensure that each file has a later timestamp on disk than the previous one.
488 base::ScopedTempDir metrics_files;
489 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
490 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
491 allocator, base_time);
492 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
493 allocator, base_time);
494 // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
495 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
497 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
498 allocator, base_time + base::Minutes(1));
500 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
502 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
503 allocator, base_time + base::Minutes(2));
505 histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
507 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
508 allocator, base_time + base::Minutes(3));
510 histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
512 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
513 allocator, base_time + base::Minutes(4));
515 base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
516 base_time + base::Minutes(5), base_time + base::Minutes(5));
518 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
519 base_time + base::Minutes(6));
521 // The global allocator has to be detached here so that no metrics created
522 // by code called below get stored in it as that would make for potential
523 // use-after-free operations if that code is called again.
524 base::GlobalHistogramAllocator::ReleaseForTesting();
526 // Register the file and allow the "checker" task to run.
527 provider()->RegisterSource(FileMetricsProvider::Params(
528 metrics_files.GetPath(),
529 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
530 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
532 // Record embedded snapshots via snapshot-manager.
533 std::vector<uint32_t> actual_order;
534 provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
535 [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
536 OnDidCreateMetricsLog();
537 task_environment()->RunUntilIdle();
539 // Files could come out in the order: a1, c2, d4, b3. They are recognizable by
540 // the number of histograms contained within each. The "0" is the last merge
541 // done, which detects that there are no more files to merge.
542 EXPECT_THAT(actual_order, testing::ElementsAre(1, 2, 4, 3, 0));
544 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
545 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
546 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
547 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
549 base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
551 base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
552 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
555 TEST_P(FileMetricsProviderTest, AccessDirectoryWithInvalidFiles) {
556 ASSERT_FALSE(PathExists(metrics_file()));
558 // Create files starting with a timestamp a few minutes back.
559 base::Time base_time = base::Time::Now() - base::Minutes(10);
561 base::ScopedTempDir metrics_files;
562 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
564 CreateMetricsFileWithHistograms(
565 metrics_files.GetPath().AppendASCII("h1.pma"),
566 base_time + base::Minutes(1), 1,
567 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
568 allocator->memory_allocator()->SetMemoryState(
569 base::PersistentMemoryAllocator::MEMORY_DELETED);
572 CreateMetricsFileWithHistograms(
573 metrics_files.GetPath().AppendASCII("h2.pma"),
574 base_time + base::Minutes(2), 2,
575 base::BindOnce(&WriteSystemProfileToAllocator));
577 CreateMetricsFileWithHistograms(
578 metrics_files.GetPath().AppendASCII("h3.pma"),
579 base_time + base::Minutes(3), 3,
580 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
581 allocator->memory_allocator()->SetMemoryState(
582 base::PersistentMemoryAllocator::MEMORY_DELETED);
586 base::File empty(metrics_files.GetPath().AppendASCII("h4.pma"),
587 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
589 base::TouchFile(metrics_files.GetPath().AppendASCII("h4.pma"),
590 base_time + base::Minutes(4), base_time + base::Minutes(4));
592 // Register the file and allow the "checker" task to run.
593 provider()->RegisterSource(FileMetricsProvider::Params(
594 metrics_files.GetPath(),
595 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
596 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
599 EXPECT_EQ(0U, GetIndependentHistogramCount());
600 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
601 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
602 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
603 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
605 // H1 should be skipped and H2 available.
606 OnDidCreateMetricsLog();
607 task_environment()->RunUntilIdle();
608 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
609 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
610 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
611 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
613 // H2 should be read and the file deleted.
614 EXPECT_EQ(2U, GetIndependentHistogramCount());
615 task_environment()->RunUntilIdle();
616 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
618 // Nothing else should be found but the last (valid but empty) file will
619 // stick around to be processed later (should it get expanded).
620 EXPECT_EQ(0U, GetIndependentHistogramCount());
621 task_environment()->RunUntilIdle();
622 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
623 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
626 TEST_P(FileMetricsProviderTest, AccessTimeLimitedDirectory) {
627 ASSERT_FALSE(PathExists(metrics_file()));
629 base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
631 base::GlobalHistogramAllocator* allocator =
632 base::GlobalHistogramAllocator::Get();
633 base::HistogramBase* histogram;
635 // Create one old file and one new file. Histogram names must be 2 characters
636 // (see HistogramFlattenerDeltaRecorder).
637 base::ScopedTempDir metrics_files;
638 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
639 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
641 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
642 allocator, base::Time::Now() - base::Hours(1));
644 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
646 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
647 allocator, base::Time::Now());
649 // The global allocator has to be detached here so that no metrics created
650 // by code called below get stored in it as that would make for potential
651 // use-after-free operations if that code is called again.
652 base::GlobalHistogramAllocator::ReleaseForTesting();
654 // Register the file and allow the "checker" task to run.
655 FileMetricsProvider::Params params(
656 metrics_files.GetPath(),
657 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
658 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
659 params.max_age = base::Minutes(30);
660 provider()->RegisterSource(params);
662 // Only b2, with 2 histograms, should be read.
663 OnDidCreateMetricsLog();
664 task_environment()->RunUntilIdle();
665 EXPECT_EQ(2U, GetSnapshotHistogramCount());
666 OnDidCreateMetricsLog();
667 task_environment()->RunUntilIdle();
668 EXPECT_EQ(0U, GetSnapshotHistogramCount());
670 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
671 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
674 TEST_P(FileMetricsProviderTest, AccessCountLimitedDirectory) {
675 ASSERT_FALSE(PathExists(metrics_file()));
677 base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
679 base::GlobalHistogramAllocator* allocator =
680 base::GlobalHistogramAllocator::Get();
681 base::HistogramBase* histogram;
683 // Create one old file and one new file. Histogram names must be 2 characters
684 // (see HistogramFlattenerDeltaRecorder).
685 base::ScopedTempDir metrics_files;
686 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
687 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
689 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
690 allocator, base::Time::Now() - base::Hours(1));
692 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
694 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
695 allocator, base::Time::Now());
697 // The global allocator has to be detached here so that no metrics created
698 // by code called below get stored in it as that would make for potential
699 // use-after-free operations if that code is called again.
700 base::GlobalHistogramAllocator::ReleaseForTesting();
702 // Register the file and allow the "checker" task to run.
703 FileMetricsProvider::Params params(
704 metrics_files.GetPath(),
705 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
706 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
707 params.max_dir_files = 1;
708 provider()->RegisterSource(params);
710 // Only b2, with 2 histograms, should be read.
711 OnDidCreateMetricsLog();
712 task_environment()->RunUntilIdle();
713 EXPECT_EQ(2U, GetSnapshotHistogramCount());
714 OnDidCreateMetricsLog();
715 task_environment()->RunUntilIdle();
716 EXPECT_EQ(0U, GetSnapshotHistogramCount());
718 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
719 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
722 TEST_P(FileMetricsProviderTest, AccessSizeLimitedDirectory) {
723 // This only works with large files that are big enough to count.
724 if (!create_large_files_)
727 ASSERT_FALSE(PathExists(metrics_file()));
729 size_t file_size_kib = 64;
730 base::GlobalHistogramAllocator::CreateWithLocalMemory(file_size_kib << 10, 0,
732 base::GlobalHistogramAllocator* allocator =
733 base::GlobalHistogramAllocator::Get();
734 base::HistogramBase* histogram;
736 // Create one old file and one new file. Histogram names must be 2 characters
737 // (see HistogramFlattenerDeltaRecorder).
738 base::ScopedTempDir metrics_files;
739 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
740 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
742 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
743 allocator, base::Time::Now() - base::Hours(1));
745 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
747 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
748 allocator, base::Time::Now());
750 // The global allocator has to be detached here so that no metrics created
751 // by code called below get stored in it as that would make for potential
752 // use-after-free operations if that code is called again.
753 base::GlobalHistogramAllocator::ReleaseForTesting();
755 // Register the file and allow the "checker" task to run.
756 FileMetricsProvider::Params params(
757 metrics_files.GetPath(),
758 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
759 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
760 params.max_dir_kib = file_size_kib + 1;
761 provider()->RegisterSource(params);
763 // Only b2, with 2 histograms, should be read.
764 OnDidCreateMetricsLog();
765 task_environment()->RunUntilIdle();
766 EXPECT_EQ(2U, GetSnapshotHistogramCount());
767 OnDidCreateMetricsLog();
768 task_environment()->RunUntilIdle();
769 EXPECT_EQ(0U, GetSnapshotHistogramCount());
771 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
772 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
775 TEST_P(FileMetricsProviderTest, AccessFilteredDirectory) {
776 ASSERT_FALSE(PathExists(metrics_file()));
778 base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
780 base::GlobalHistogramAllocator* allocator =
781 base::GlobalHistogramAllocator::Get();
782 base::HistogramBase* histogram;
784 // Create files starting with a timestamp a few minutes back.
785 base::Time base_time = base::Time::Now() - base::Minutes(10);
787 // Create some files in an odd order. The files are "touched" back in time to
788 // ensure that each file has a later timestamp on disk than the previous one.
789 base::ScopedTempDir metrics_files;
790 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
791 // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
792 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
794 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
795 allocator, base_time + base::Minutes(1));
797 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
799 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
800 allocator, base_time + base::Minutes(2));
802 histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
804 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
805 allocator, base_time + base::Minutes(3));
807 histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
809 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
810 allocator, base_time + base::Minutes(4));
812 base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
813 base_time + base::Minutes(5), base_time + base::Minutes(5));
815 // The global allocator has to be detached here so that no metrics created
816 // by code called below get stored in it as that would make for potential
817 // use-after-free operations if that code is called again.
818 base::GlobalHistogramAllocator::ReleaseForTesting();
820 // Register the file and allow the "checker" task to run.
821 FileMetricsProvider::Params params(
822 metrics_files.GetPath(),
823 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
824 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
825 const FileMetricsProvider::FilterAction actions[] = {
826 FileMetricsProvider::FILTER_PROCESS_FILE, // a1
827 FileMetricsProvider::FILTER_TRY_LATER, // c2
828 FileMetricsProvider::FILTER_SKIP_FILE, // d4
829 FileMetricsProvider::FILTER_PROCESS_FILE, // b3
830 FileMetricsProvider::FILTER_PROCESS_FILE}; // c2 (again)
831 SetFilterActions(¶ms, actions, std::size(actions));
832 provider()->RegisterSource(params);
834 // Record embedded snapshots via snapshot-manager.
835 std::vector<uint32_t> actual_order;
836 provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
837 [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
838 OnDidCreateMetricsLog();
839 task_environment()->RunUntilIdle();
841 // Files could come out in the order: a1, b3, c2. They are recognizable by the
842 // number of histograms contained within each. The "0" is the last merge done,
843 // which detects that there are no more files to merge.
844 EXPECT_THAT(actual_order, testing::ElementsAre(1, 3, 2, 0));
846 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
847 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
848 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
849 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
852 TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
853 // Create a global histogram allocator that maps to a file.
854 ASSERT_FALSE(PathExists(metrics_file()));
855 base::GlobalHistogramAllocator::CreateWithFile(
857 create_large_files_ ? kLargeFileSize : kSmallFileSize,
859 CreateGlobalHistograms(2);
860 ASSERT_TRUE(PathExists(metrics_file()));
861 base::HistogramBase* h0 = GetCreatedHistogram(0);
862 base::HistogramBase* h1 = GetCreatedHistogram(1);
865 base::GlobalHistogramAllocator::ReleaseForTesting();
867 // Register the file and allow the "checker" task to run.
868 provider()->RegisterSource(FileMetricsProvider::Params(
869 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
870 FileMetricsProvider::ASSOCIATE_CURRENT_RUN));
872 // Record embedded snapshots via snapshot-manager.
873 OnDidCreateMetricsLog();
874 task_environment()->RunUntilIdle();
875 EXPECT_EQ(2U, GetSnapshotHistogramCount());
876 EXPECT_TRUE(base::PathExists(metrics_file()));
878 // Make sure a second call to the snapshot-recorder doesn't break anything.
879 OnDidCreateMetricsLog();
880 task_environment()->RunUntilIdle();
881 EXPECT_EQ(0U, GetSnapshotHistogramCount());
882 EXPECT_TRUE(base::PathExists(metrics_file()));
884 // Change a histogram and ensure that it's counted.
886 EXPECT_EQ(1U, GetSnapshotHistogramCount());
887 EXPECT_TRUE(base::PathExists(metrics_file()));
889 // Change the other histogram and verify.
891 EXPECT_EQ(1U, GetSnapshotHistogramCount());
892 EXPECT_TRUE(base::PathExists(metrics_file()));
895 TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
896 ASSERT_FALSE(PathExists(metrics_file()));
897 CreateMetricsFileWithHistograms(2);
899 // Register the file and allow the "checker" task to run.
900 ASSERT_TRUE(PathExists(metrics_file()));
901 provider()->RegisterSource(FileMetricsProvider::Params(
902 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
903 FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName));
905 // Record embedded snapshots via snapshot-manager.
906 ASSERT_TRUE(HasPreviousSessionData());
907 task_environment()->RunUntilIdle();
909 HistogramFlattenerDeltaRecorder flattener;
910 base::HistogramSnapshotManager snapshot_manager(&flattener);
911 RecordInitialHistogramSnapshots(&snapshot_manager);
912 EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
914 EXPECT_TRUE(base::PathExists(metrics_file()));
915 OnDidCreateMetricsLog();
916 task_environment()->RunUntilIdle();
917 EXPECT_FALSE(base::PathExists(metrics_file()));
919 // A run for normal histograms should produce nothing.
920 CreateMetricsFileWithHistograms(2);
921 OnDidCreateMetricsLog();
922 task_environment()->RunUntilIdle();
923 EXPECT_EQ(0U, GetSnapshotHistogramCount());
924 EXPECT_TRUE(base::PathExists(metrics_file()));
925 OnDidCreateMetricsLog();
926 task_environment()->RunUntilIdle();
927 EXPECT_TRUE(base::PathExists(metrics_file()));
930 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithoutProfile) {
931 ASSERT_FALSE(PathExists(metrics_file()));
932 CreateMetricsFileWithHistograms(2);
934 // Register the file and allow the "checker" task to run.
935 ASSERT_TRUE(PathExists(metrics_file()));
936 provider()->RegisterSource(FileMetricsProvider::Params(
937 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
938 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
940 // Record embedded snapshots via snapshot-manager.
941 OnDidCreateMetricsLog();
942 task_environment()->RunUntilIdle();
944 HistogramFlattenerDeltaRecorder flattener;
945 base::HistogramSnapshotManager snapshot_manager(&flattener);
946 ChromeUserMetricsExtension uma_proto;
948 // A read of metrics with internal profiles should return nothing.
949 EXPECT_FALSE(HasIndependentMetrics());
950 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
952 EXPECT_TRUE(base::PathExists(metrics_file()));
953 OnDidCreateMetricsLog();
954 task_environment()->RunUntilIdle();
955 EXPECT_FALSE(base::PathExists(metrics_file()));
958 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithProfile) {
959 ASSERT_FALSE(PathExists(metrics_file()));
960 CreateMetricsFileWithHistograms(
961 metrics_file(), base::Time::Now(), 2,
962 base::BindOnce(&WriteSystemProfileToAllocator));
964 // Register the file and allow the "checker" task to run.
965 ASSERT_TRUE(PathExists(metrics_file()));
966 provider()->RegisterSource(FileMetricsProvider::Params(
967 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
968 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
970 // Record embedded snapshots via snapshot-manager.
971 OnDidCreateMetricsLog();
972 task_environment()->RunUntilIdle();
974 HistogramFlattenerDeltaRecorder flattener;
975 base::HistogramSnapshotManager snapshot_manager(&flattener);
976 RecordInitialHistogramSnapshots(&snapshot_manager);
977 EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
979 // A read of metrics with internal profiles should return one result, and
980 // the independent log generated should have the embedded system profile.
981 ChromeUserMetricsExtension uma_proto;
982 EXPECT_TRUE(HasIndependentMetrics());
983 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
984 ASSERT_TRUE(uma_proto.has_system_profile());
985 ASSERT_EQ(1, uma_proto.system_profile().field_trial_size());
986 EXPECT_EQ(123U, uma_proto.system_profile().field_trial(0).name_id());
987 EXPECT_EQ(456U, uma_proto.system_profile().field_trial(0).group_id());
988 EXPECT_FALSE(HasIndependentMetrics());
989 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
991 task_environment()->RunUntilIdle();
992 EXPECT_FALSE(base::PathExists(metrics_file()));
995 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithoutProfile) {
996 ASSERT_FALSE(PathExists(metrics_file()));
997 CreateMetricsFileWithHistograms(2);
999 // Register the file and allow the "checker" task to run.
1000 ASSERT_TRUE(PathExists(metrics_file()));
1001 provider()->RegisterSource(FileMetricsProvider::Params(
1002 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1003 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1006 // Record embedded snapshots via snapshot-manager.
1007 ASSERT_TRUE(HasPreviousSessionData());
1008 task_environment()->RunUntilIdle();
1010 HistogramFlattenerDeltaRecorder flattener;
1011 base::HistogramSnapshotManager snapshot_manager(&flattener);
1012 RecordInitialHistogramSnapshots(&snapshot_manager);
1013 EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
1015 // A read of metrics with internal profiles should return nothing.
1016 ChromeUserMetricsExtension uma_proto;
1017 EXPECT_FALSE(HasIndependentMetrics());
1018 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1020 EXPECT_TRUE(base::PathExists(metrics_file()));
1021 OnDidCreateMetricsLog();
1022 task_environment()->RunUntilIdle();
1023 EXPECT_FALSE(base::PathExists(metrics_file()));
1026 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithProfile) {
1027 ASSERT_FALSE(PathExists(metrics_file()));
1028 CreateMetricsFileWithHistograms(
1029 metrics_file(), base::Time::Now(), 2,
1030 base::BindOnce(&WriteSystemProfileToAllocator));
1032 // Register the file and allow the "checker" task to run.
1033 ASSERT_TRUE(PathExists(metrics_file()));
1034 provider()->RegisterSource(FileMetricsProvider::Params(
1035 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1036 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1039 // Record embedded snapshots via snapshot-manager.
1040 EXPECT_FALSE(HasPreviousSessionData());
1041 task_environment()->RunUntilIdle();
1043 HistogramFlattenerDeltaRecorder flattener;
1044 base::HistogramSnapshotManager snapshot_manager(&flattener);
1045 RecordInitialHistogramSnapshots(&snapshot_manager);
1046 EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
1048 // A read of metrics with internal profiles should return one result.
1049 ChromeUserMetricsExtension uma_proto;
1050 EXPECT_TRUE(HasIndependentMetrics());
1051 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1052 EXPECT_FALSE(HasIndependentMetrics());
1053 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1055 task_environment()->RunUntilIdle();
1056 EXPECT_FALSE(base::PathExists(metrics_file()));
1059 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsFromDir) {
1060 const int file_count = 3;
1061 base::Time file_base_time = base::Time::Now();
1062 std::vector<base::FilePath> file_names;
1063 for (int i = 0; i < file_count; ++i) {
1064 CreateMetricsFileWithHistograms(
1065 metrics_file(), base::Time::Now(), 2,
1066 base::BindOnce(&WriteSystemProfileToAllocator));
1067 ASSERT_TRUE(PathExists(metrics_file()));
1068 char new_name[] = "hX";
1069 new_name[1] = '1' + i;
1070 base::FilePath file_name = temp_dir().AppendASCII(new_name).AddExtension(
1071 base::PersistentMemoryAllocator::kFileExtension);
1072 base::Time file_time = file_base_time - base::Minutes(file_count - i);
1073 base::TouchFile(metrics_file(), file_time, file_time);
1074 base::Move(metrics_file(), file_name);
1075 file_names.push_back(std::move(file_name));
1078 // Register the file and allow the "checker" task to run.
1079 provider()->RegisterSource(FileMetricsProvider::Params(
1080 temp_dir(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
1081 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE));
1083 OnDidCreateMetricsLog();
1084 task_environment()->RunUntilIdle();
1086 // A read of metrics with internal profiles should return one result.
1087 HistogramFlattenerDeltaRecorder flattener;
1088 base::HistogramSnapshotManager snapshot_manager(&flattener);
1089 ChromeUserMetricsExtension uma_proto;
1090 for (int i = 0; i < file_count; ++i) {
1091 EXPECT_TRUE(HasIndependentMetrics()) << i;
1092 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager)) << i;
1093 task_environment()->RunUntilIdle();
1095 EXPECT_FALSE(HasIndependentMetrics());
1096 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1098 OnDidCreateMetricsLog();
1099 task_environment()->RunUntilIdle();
1100 for (const auto& file_name : file_names)
1101 EXPECT_FALSE(base::PathExists(file_name));
1104 TEST_P(FileMetricsProviderTest,
1105 RecordInitialHistogramSnapshotsStabilityHistograms) {
1106 // Create a metrics file with 2 non-stability histograms and 2 stability
1107 // histograms. Histogram names must be 2 characters (see
1108 // HistogramFlattenerDeltaRecorder).
1109 ASSERT_FALSE(PathExists(metrics_file()));
1110 base::GlobalHistogramAllocator::CreateWithLocalMemory(
1111 create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1112 base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1113 "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1115 base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1116 "h1", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1118 base::HistogramBase* h2 = base::Histogram::FactoryGet(
1120 /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1122 base::HistogramBase* h3 = base::Histogram::FactoryGet(
1124 /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1126 base::GlobalHistogramAllocator* histogram_allocator =
1127 base::GlobalHistogramAllocator::ReleaseForTesting();
1128 WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1130 ASSERT_TRUE(PathExists(metrics_file()));
1132 // Register the file and allow the "checker" task to run.
1133 provider()->RegisterSource(FileMetricsProvider::Params(
1134 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1135 FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName));
1136 ASSERT_TRUE(HasPreviousSessionData());
1137 task_environment()->RunUntilIdle();
1139 // Record embedded snapshots via snapshot-manager.
1140 HistogramFlattenerDeltaRecorder flattener;
1141 base::HistogramSnapshotManager snapshot_manager(&flattener);
1142 RecordInitialHistogramSnapshots(&snapshot_manager);
1144 // Verify that only the stability histograms were snapshotted.
1145 EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1146 testing::ElementsAre("h0", "h2"));
1148 // The metrics file should eventually be deleted.
1149 EXPECT_TRUE(base::PathExists(metrics_file()));
1150 OnDidCreateMetricsLog();
1151 task_environment()->RunUntilIdle();
1152 EXPECT_FALSE(base::PathExists(metrics_file()));
1155 TEST_P(FileMetricsProviderTest, IndependentLogContainsUmaHistograms) {
1156 ASSERT_FALSE(PathExists(metrics_file()));
1157 // Create a metrics file with 2 UMA histograms and 2 non-UMA histograms.
1158 // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
1159 base::GlobalHistogramAllocator::CreateWithLocalMemory(
1160 create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1161 base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1162 "h0", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1164 base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1165 "h1", /*flags=*/base::HistogramBase::Flags::kNoFlags);
1167 base::HistogramBase* h2 = base::Histogram::FactoryGet(
1169 /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1171 base::HistogramBase* h3 = base::Histogram::FactoryGet(
1173 /*flags=*/base::HistogramBase::Flags::kNoFlags);
1175 base::GlobalHistogramAllocator* histogram_allocator =
1176 base::GlobalHistogramAllocator::ReleaseForTesting();
1177 // Write a system profile so that an independent log can successfully be
1178 // created from the metrics file.
1179 WriteSystemProfileToAllocator(histogram_allocator);
1180 WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1182 ASSERT_TRUE(PathExists(metrics_file()));
1184 // Register the file and allow the "checker" task to run.
1185 provider()->RegisterSource(FileMetricsProvider::Params(
1186 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1187 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1188 OnDidCreateMetricsLog();
1189 task_environment()->RunUntilIdle();
1191 // Verify that the independent log provided only contains UMA histograms (both
1192 // stability and non-stability).
1193 ChromeUserMetricsExtension uma_proto;
1194 HistogramFlattenerDeltaRecorder flattener;
1195 base::HistogramSnapshotManager snapshot_manager(&flattener);
1196 EXPECT_TRUE(HasIndependentMetrics());
1197 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1198 EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1199 testing::ElementsAre("h0", "h2"));
1201 // The metrics file should eventually be deleted.
1202 task_environment()->RunUntilIdle();
1203 EXPECT_FALSE(base::PathExists(metrics_file()));
1206 // Verifies that if the embedded system profile in the file does not contain
1207 // a client UUID, the generated independent log's client ID is not overwritten.
1208 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithoutClientUuid) {
1209 ASSERT_FALSE(PathExists(metrics_file()));
1210 CreateMetricsFileWithHistograms(
1211 metrics_file(), base::Time::Now(), 2,
1212 base::BindOnce(&WriteSystemProfileToAllocator));
1214 // Register the file and allow the "checker" task to run.
1215 ASSERT_TRUE(PathExists(metrics_file()));
1216 provider()->RegisterSource(FileMetricsProvider::Params(
1217 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1218 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1220 // Record embedded snapshots via snapshot-manager.
1221 OnDidCreateMetricsLog();
1222 task_environment()->RunUntilIdle();
1224 HistogramFlattenerDeltaRecorder flattener;
1225 base::HistogramSnapshotManager snapshot_manager(&flattener);
1227 // Since the embedded system profile has no client_uuid set (see
1228 // WriteSystemProfileToAllocator()), the client ID written in |uma_proto|
1230 ChromeUserMetricsExtension uma_proto;
1231 uma_proto.set_client_id(1);
1232 EXPECT_TRUE(HasIndependentMetrics());
1233 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1234 EXPECT_EQ(uma_proto.client_id(), 1U);
1236 task_environment()->RunUntilIdle();
1237 EXPECT_FALSE(base::PathExists(metrics_file()));
1240 // Verifies that if the embedded system profile in the file contains a client
1241 // UUID, it is used as the generated independent log's client ID.
1242 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithClientUuid) {
1243 ASSERT_FALSE(PathExists(metrics_file()));
1244 static constexpr char kProfileClientUuid[] = "abc";
1245 CreateMetricsFileWithHistograms(
1246 metrics_file(), base::Time::Now(), 2,
1247 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
1248 metrics::SystemProfileProto profile_proto;
1249 profile_proto.set_client_uuid(kProfileClientUuid);
1251 metrics::PersistentSystemProfile persistent_profile;
1252 persistent_profile.RegisterPersistentAllocator(
1253 allocator->memory_allocator());
1254 persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
1257 // Register the file and allow the "checker" task to run.
1258 ASSERT_TRUE(PathExists(metrics_file()));
1259 provider()->RegisterSource(FileMetricsProvider::Params(
1260 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1261 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1263 // Record embedded snapshots via snapshot-manager.
1264 OnDidCreateMetricsLog();
1265 task_environment()->RunUntilIdle();
1267 HistogramFlattenerDeltaRecorder flattener;
1268 base::HistogramSnapshotManager snapshot_manager(&flattener);
1270 // Since the embedded system profile contains a client_uuid, the client ID
1271 // in |uma_proto| should be overwritten.
1272 ChromeUserMetricsExtension uma_proto;
1273 uma_proto.set_client_id(1);
1274 EXPECT_TRUE(HasIndependentMetrics());
1275 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1276 EXPECT_NE(uma_proto.client_id(), 1U);
1277 EXPECT_EQ(uma_proto.client_id(), MetricsLog::Hash(kProfileClientUuid));
1279 task_environment()->RunUntilIdle();
1280 EXPECT_FALSE(base::PathExists(metrics_file()));
1283 } // namespace metrics