xref: /aosp_15_r20/external/cronet/components/metrics/file_metrics_provider_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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.
4 
5 #include "components/metrics/file_metrics_provider.h"
6 
7 #include <memory>
8 
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"
39 
40 namespace {
41 const char kMetricsName[] = "TestMetrics";
42 const char kMergedCountHistogramName[] =
43     "UMA.FileMetricsProvider.TestMetrics.MergedHistogramsCount";
44 const char kMetricsFilename[] = "file.metrics";
45 
WriteSystemProfileToAllocator(base::PersistentHistogramAllocator * allocator)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. Similarly for the session
51   // hash.
52   metrics::SystemProfileProto::FieldTrial* trial =
53       profile_proto.add_field_trial();
54   trial->set_name_id(123);
55   trial->set_group_id(456);
56   profile_proto.set_session_hash(789);
57   metrics::PersistentSystemProfile persistent_profile;
58   persistent_profile.RegisterPersistentAllocator(allocator->memory_allocator());
59   persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
60 }
61 }  // namespace
62 
63 namespace metrics {
64 
65 class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
66  public:
67   HistogramFlattenerDeltaRecorder() = default;
68 
69   HistogramFlattenerDeltaRecorder(const HistogramFlattenerDeltaRecorder&) =
70       delete;
71   HistogramFlattenerDeltaRecorder& operator=(
72       const HistogramFlattenerDeltaRecorder&) = delete;
73 
RecordDelta(const base::HistogramBase & histogram,const base::HistogramSamples & snapshot)74   void RecordDelta(const base::HistogramBase& histogram,
75                    const base::HistogramSamples& snapshot) override {
76     // Only remember locally created histograms; they have exactly 2 chars.
77     if (strlen(histogram.histogram_name()) == 2)
78       recorded_delta_histogram_names_.push_back(histogram.histogram_name());
79   }
80 
GetRecordedDeltaHistogramNames()81   std::vector<std::string> GetRecordedDeltaHistogramNames() {
82     return recorded_delta_histogram_names_;
83   }
84 
85  private:
86   std::vector<std::string> recorded_delta_histogram_names_;
87 };
88 
89 // Exactly the same as FileMetricsProvider, but provides a way to "hook" into
90 // RecordSourcesChecked() and run a callback each time it is called so that it
91 // is easier to individually verify the sources being merged.
92 class TestFileMetricsProvider : public FileMetricsProvider {
93  public:
94   using FileMetricsProvider::FileMetricsProvider;
95 
96   TestFileMetricsProvider(const TestFileMetricsProvider&) = delete;
97   TestFileMetricsProvider& operator=(const TestFileMetricsProvider&) = delete;
98 
99   ~TestFileMetricsProvider() override = default;
100 
101   // Sets the callback to run after RecordSourcesChecked() is called. Used to
102   // individually verify the sources being merged.
SetSourcesCheckedCallback(base::RepeatingClosure callback)103   void SetSourcesCheckedCallback(base::RepeatingClosure callback) {
104     callback_ = std::move(callback);
105   }
106 
107  private:
108   // FileMetricsProvider:
RecordSourcesChecked(SourceInfoList * checked,std::vector<size_t> samples_counts)109   void RecordSourcesChecked(SourceInfoList* checked,
110                             std::vector<size_t> samples_counts) override {
111     if (!callback_.is_null()) {
112       callback_.Run();
113     }
114 
115     FileMetricsProvider::RecordSourcesChecked(checked, samples_counts);
116   }
117 
118   // A callback to run after a call to RecordSourcesChecked().
119   base::RepeatingClosure callback_;
120 };
121 
122 class FileMetricsProviderTest : public testing::TestWithParam<bool> {
123  public:
124   FileMetricsProviderTest(const FileMetricsProviderTest&) = delete;
125   FileMetricsProviderTest& operator=(const FileMetricsProviderTest&) = delete;
126 
127  protected:
128   const size_t kSmallFileSize = 64 << 10;  // 64 KiB
129   const size_t kLargeFileSize =  2 << 20;  //  2 MiB
130 
131   enum : int { kMaxCreateHistograms = 10 };
132 
FileMetricsProviderTest()133   FileMetricsProviderTest()
134       : create_large_files_(GetParam()),
135         statistics_recorder_(
136             base::StatisticsRecorder::CreateTemporaryForTesting()),
137         prefs_(new TestingPrefServiceSimple) {
138     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
139     FileMetricsProvider::RegisterSourcePrefs(prefs_->registry(), kMetricsName);
140   }
141 
~FileMetricsProviderTest()142   ~FileMetricsProviderTest() override {
143     // Clear out any final remaining tasks.
144     task_environment_.RunUntilIdle();
145     DCHECK_EQ(0U, filter_actions_remaining_);
146     // If a global histogram allocator exists at this point then it likely
147     // acquired histograms that will continue to point to the released
148     // memory and potentially cause use-after-free memory corruption.
149     DCHECK(!base::GlobalHistogramAllocator::Get());
150   }
151 
task_environment()152   base::test::TaskEnvironment* task_environment() { return &task_environment_; }
prefs()153   TestingPrefServiceSimple* prefs() { return prefs_.get(); }
temp_dir()154   base::FilePath temp_dir() { return temp_dir_.GetPath(); }
metrics_file()155   base::FilePath metrics_file() {
156     return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
157   }
158 
provider()159   TestFileMetricsProvider* provider() {
160     if (!provider_)
161       provider_ = std::make_unique<TestFileMetricsProvider>(prefs());
162     return provider_.get();
163   }
164 
OnDidCreateMetricsLog()165   void OnDidCreateMetricsLog() {
166     provider()->OnDidCreateMetricsLog();
167   }
168 
HasPreviousSessionData()169   bool HasPreviousSessionData() { return provider()->HasPreviousSessionData(); }
170 
MergeHistogramDeltas()171   void MergeHistogramDeltas() {
172     provider()->MergeHistogramDeltas(/*async=*/false,
173                                      /*done_callback=*/base::DoNothing());
174   }
175 
HasIndependentMetrics()176   bool HasIndependentMetrics() { return provider()->HasIndependentMetrics(); }
177 
ProvideIndependentMetrics(ChromeUserMetricsExtension * uma_proto,base::HistogramSnapshotManager * snapshot_manager)178   bool ProvideIndependentMetrics(
179       ChromeUserMetricsExtension* uma_proto,
180       base::HistogramSnapshotManager* snapshot_manager) {
181     bool success = false;
182     bool success_set = false;
183     provider()->ProvideIndependentMetrics(
184         base::DoNothing(),
185         base::BindOnce(
186             [](bool* success_ptr, bool* set_ptr, bool s) {
187               *success_ptr = s;
188               *set_ptr = true;
189             },
190             &success, &success_set),
191         uma_proto, snapshot_manager);
192 
193     task_environment()->RunUntilIdle();
194     CHECK(success_set);
195     return success;
196   }
197 
RecordInitialHistogramSnapshots(base::HistogramSnapshotManager * snapshot_manager)198   void RecordInitialHistogramSnapshots(
199       base::HistogramSnapshotManager* snapshot_manager) {
200     provider()->RecordInitialHistogramSnapshots(snapshot_manager);
201   }
202 
GetSnapshotHistogramCount()203   size_t GetSnapshotHistogramCount() {
204     // Merge the data from the allocator into the StatisticsRecorder.
205     MergeHistogramDeltas();
206 
207     // Flatten what is known to see what has changed since the last time.
208     HistogramFlattenerDeltaRecorder flattener;
209     base::HistogramSnapshotManager snapshot_manager(&flattener);
210     // "true" to the begin() includes histograms held in persistent storage.
211     base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
212                                             base::Histogram::kNoFlags,
213                                             &snapshot_manager);
214     return flattener.GetRecordedDeltaHistogramNames().size();
215   }
216 
GetIndependentHistogramCount()217   size_t GetIndependentHistogramCount() {
218     HistogramFlattenerDeltaRecorder flattener;
219     base::HistogramSnapshotManager snapshot_manager(&flattener);
220     ChromeUserMetricsExtension uma_proto;
221     provider()->ProvideIndependentMetrics(base::DoNothing(),
222                                           base::BindOnce([](bool success) {}),
223                                           &uma_proto, &snapshot_manager);
224 
225     task_environment()->RunUntilIdle();
226     return flattener.GetRecordedDeltaHistogramNames().size();
227   }
228 
CreateGlobalHistograms(int histogram_count)229   void CreateGlobalHistograms(int histogram_count) {
230     DCHECK_GT(kMaxCreateHistograms, histogram_count);
231 
232     // Create both sparse and normal histograms in the allocator. Make them
233     // stability histograms to ensure that the histograms are snapshotted (in
234     // the case of stability logs) or are put into independent logs. Histogram
235     // names must be 2 characters (see HistogramFlattenerDeltaRecorder).
236     created_histograms_[0] = base::SparseHistogram::FactoryGet(
237         "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
238     created_histograms_[0]->Add(0);
239     for (int i = 1; i < histogram_count; ++i) {
240       created_histograms_[i] = base::Histogram::FactoryGet(
241           base::StringPrintf("h%d", i), 1, 100, 10,
242           /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
243       created_histograms_[i]->Add(i);
244     }
245   }
246 
WriteMetricsFile(const base::FilePath & path,base::PersistentHistogramAllocator * metrics)247   void WriteMetricsFile(const base::FilePath& path,
248                         base::PersistentHistogramAllocator* metrics) {
249     base::File writer(path,
250                       base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
251     // Use DCHECK so the stack-trace will indicate where this was called.
252     DCHECK(writer.IsValid()) << path;
253     size_t file_size = create_large_files_ ? metrics->size() : metrics->used();
254     int written = writer.Write(0, (const char*)metrics->data(), file_size);
255     DCHECK_EQ(static_cast<int>(file_size), written);
256   }
257 
WriteMetricsFileAtTime(const base::FilePath & path,base::PersistentHistogramAllocator * metrics,base::Time write_time)258   void WriteMetricsFileAtTime(const base::FilePath& path,
259                               base::PersistentHistogramAllocator* metrics,
260                               base::Time write_time) {
261     WriteMetricsFile(path, metrics);
262     base::TouchFile(path, write_time, write_time);
263   }
264 
CreateMetricsFileWithHistograms(const base::FilePath & file_path,base::Time write_time,int histogram_count,base::OnceCallback<void (base::PersistentHistogramAllocator *)> callback)265   base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
266       const base::FilePath& file_path,
267       base::Time write_time,
268       int histogram_count,
269       base::OnceCallback<void(base::PersistentHistogramAllocator*)> callback) {
270     base::GlobalHistogramAllocator::CreateWithLocalMemory(
271         create_large_files_ ? kLargeFileSize : kSmallFileSize,
272         0, kMetricsName);
273 
274     CreateGlobalHistograms(histogram_count);
275 
276     base::GlobalHistogramAllocator* histogram_allocator =
277         base::GlobalHistogramAllocator::ReleaseForTesting();
278     std::move(callback).Run(histogram_allocator);
279 
280     WriteMetricsFileAtTime(file_path, histogram_allocator, write_time);
281     return histogram_allocator;
282   }
283 
CreateMetricsFileWithHistograms(int histogram_count)284   base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
285       int histogram_count) {
286     return CreateMetricsFileWithHistograms(
287         metrics_file(), base::Time::Now(), histogram_count,
288         base::BindOnce([](base::PersistentHistogramAllocator* allocator) {}));
289   }
290 
GetCreatedHistogram(int index)291   base::HistogramBase* GetCreatedHistogram(int index) {
292     DCHECK_GT(kMaxCreateHistograms, index);
293     return created_histograms_[index];
294   }
295 
SetFilterActions(FileMetricsProvider::Params * params,const FileMetricsProvider::FilterAction * actions,size_t count)296   void SetFilterActions(FileMetricsProvider::Params* params,
297                         const FileMetricsProvider::FilterAction* actions,
298                         size_t count) {
299     filter_actions_ = actions;
300     filter_actions_remaining_ = count;
301     params->filter = base::BindRepeating(
302         &FileMetricsProviderTest::FilterSourcePath, base::Unretained(this));
303   }
304 
305   const bool create_large_files_;
306 
307  private:
FilterSourcePath(const base::FilePath & path)308   FileMetricsProvider::FilterAction FilterSourcePath(
309       const base::FilePath& path) {
310     DCHECK_LT(0U, filter_actions_remaining_);
311     --filter_actions_remaining_;
312     return *filter_actions_++;
313   }
314 
315   base::test::TaskEnvironment task_environment_;
316   std::unique_ptr<base::StatisticsRecorder> statistics_recorder_;
317   base::ScopedTempDir temp_dir_;
318   std::unique_ptr<TestingPrefServiceSimple> prefs_;
319   std::unique_ptr<TestFileMetricsProvider> provider_;
320   base::HistogramBase* created_histograms_[kMaxCreateHistograms];
321 
322   raw_ptr<const FileMetricsProvider::FilterAction, AllowPtrArithmetic>
323       filter_actions_ = nullptr;
324   size_t filter_actions_remaining_ = 0;
325 };
326 
327 // Run all test cases with both small and large files.
328 INSTANTIATE_TEST_SUITE_P(SmallAndLargeFiles,
329                          FileMetricsProviderTest,
330                          testing::Bool());
331 
TEST_P(FileMetricsProviderTest,AccessMetrics)332 TEST_P(FileMetricsProviderTest, AccessMetrics) {
333   ASSERT_FALSE(PathExists(metrics_file()));
334   base::HistogramTester histogram_tester;
335 
336   base::Time metrics_time = base::Time::Now() - base::Minutes(5);
337   base::GlobalHistogramAllocator* histogram_allocator =
338       CreateMetricsFileWithHistograms(2);
339   ASSERT_TRUE(PathExists(metrics_file()));
340   base::TouchFile(metrics_file(), metrics_time, metrics_time);
341 
342   // Register the file and allow the "checker" task to run.
343   provider()->RegisterSource(FileMetricsProvider::Params(
344       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
345       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
346   histogram_tester.ExpectTotalCount(kMergedCountHistogramName,
347                                     /*expected_count=*/0);
348 
349   // Record embedded snapshots via snapshot-manager.
350   OnDidCreateMetricsLog();
351   task_environment()->RunUntilIdle();
352   EXPECT_EQ(2U, GetSnapshotHistogramCount());
353   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
354                                       /*expected_bucket_count=*/1);
355   EXPECT_FALSE(base::PathExists(metrics_file()));
356 
357   // Make sure a second call to the snapshot-recorder doesn't break anything.
358   OnDidCreateMetricsLog();
359   task_environment()->RunUntilIdle();
360   EXPECT_EQ(0U, GetSnapshotHistogramCount());
361 
362   // File should have been deleted but recreate it to test behavior should
363   // the file not be deletable by this process.
364   WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
365 
366   // Second full run on the same file should produce nothing.
367   OnDidCreateMetricsLog();
368   task_environment()->RunUntilIdle();
369   EXPECT_EQ(0U, GetSnapshotHistogramCount());
370   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
371                                       /*expected_bucket_count=*/1);
372   EXPECT_FALSE(base::PathExists(metrics_file()));
373 
374   // Recreate the file to indicate that it is "new" and must be recorded.
375   metrics_time = metrics_time + base::Minutes(1);
376   WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
377 
378   // This run should again have "new" histograms.
379   OnDidCreateMetricsLog();
380   task_environment()->RunUntilIdle();
381   EXPECT_EQ(2U, GetSnapshotHistogramCount());
382   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
383                                       /*expected_bucket_count=*/2);
384   EXPECT_FALSE(base::PathExists(metrics_file()));
385 }
386 
TEST_P(FileMetricsProviderTest,AccessTimeLimitedFile)387 TEST_P(FileMetricsProviderTest, AccessTimeLimitedFile) {
388   ASSERT_FALSE(PathExists(metrics_file()));
389 
390   base::Time metrics_time = base::Time::Now() - base::Hours(5);
391   CreateMetricsFileWithHistograms(2);
392   ASSERT_TRUE(PathExists(metrics_file()));
393   base::TouchFile(metrics_file(), metrics_time, metrics_time);
394 
395   // Register the file and allow the "checker" task to run.
396   FileMetricsProvider::Params params(
397       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
398       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
399   params.max_age = base::Hours(1);
400   provider()->RegisterSource(params);
401 
402   // Attempt to access the file should return nothing.
403   OnDidCreateMetricsLog();
404   task_environment()->RunUntilIdle();
405   EXPECT_EQ(0U, GetSnapshotHistogramCount());
406   EXPECT_FALSE(base::PathExists(metrics_file()));
407 }
408 
TEST_P(FileMetricsProviderTest,FilterDelaysFile)409 TEST_P(FileMetricsProviderTest, FilterDelaysFile) {
410   ASSERT_FALSE(PathExists(metrics_file()));
411 
412   base::Time now_time = base::Time::Now();
413   base::Time metrics_time = now_time - base::Minutes(5);
414   CreateMetricsFileWithHistograms(2);
415   ASSERT_TRUE(PathExists(metrics_file()));
416   base::TouchFile(metrics_file(), metrics_time, metrics_time);
417   base::File::Info fileinfo;
418   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
419   EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
420 
421   // Register the file and allow the "checker" task to run.
422   FileMetricsProvider::Params params(
423       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
424       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
425   const FileMetricsProvider::FilterAction actions[] = {
426       FileMetricsProvider::FILTER_TRY_LATER,
427       FileMetricsProvider::FILTER_PROCESS_FILE};
428   SetFilterActions(&params, actions, std::size(actions));
429   provider()->RegisterSource(params);
430 
431   // Processing the file should touch it but yield no results. File timestamp
432   // accuracy is limited so compare the touched time to a couple seconds past.
433   OnDidCreateMetricsLog();
434   task_environment()->RunUntilIdle();
435   EXPECT_EQ(0U, GetSnapshotHistogramCount());
436   EXPECT_TRUE(base::PathExists(metrics_file()));
437   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
438   EXPECT_LT(metrics_time, fileinfo.last_modified);
439   EXPECT_LE(now_time - base::Seconds(2), fileinfo.last_modified);
440 
441   // Second full run on the same file should process the file.
442   OnDidCreateMetricsLog();
443   task_environment()->RunUntilIdle();
444   EXPECT_EQ(2U, GetSnapshotHistogramCount());
445   EXPECT_FALSE(base::PathExists(metrics_file()));
446 }
447 
TEST_P(FileMetricsProviderTest,FilterSkipsFile)448 TEST_P(FileMetricsProviderTest, FilterSkipsFile) {
449   ASSERT_FALSE(PathExists(metrics_file()));
450 
451   base::Time now_time = base::Time::Now();
452   base::Time metrics_time = now_time - base::Minutes(5);
453   CreateMetricsFileWithHistograms(2);
454   ASSERT_TRUE(PathExists(metrics_file()));
455   base::TouchFile(metrics_file(), metrics_time, metrics_time);
456   base::File::Info fileinfo;
457   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
458   EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
459 
460   // Register the file and allow the "checker" task to run.
461   FileMetricsProvider::Params params(
462       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
463       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
464   const FileMetricsProvider::FilterAction actions[] = {
465       FileMetricsProvider::FILTER_SKIP_FILE};
466   SetFilterActions(&params, actions, std::size(actions));
467   provider()->RegisterSource(params);
468 
469   // Processing the file should delete it.
470   OnDidCreateMetricsLog();
471   task_environment()->RunUntilIdle();
472   EXPECT_EQ(0U, GetSnapshotHistogramCount());
473   EXPECT_FALSE(base::PathExists(metrics_file()));
474 }
475 
TEST_P(FileMetricsProviderTest,AccessDirectory)476 TEST_P(FileMetricsProviderTest, AccessDirectory) {
477   ASSERT_FALSE(PathExists(metrics_file()));
478 
479   base::GlobalHistogramAllocator::CreateWithLocalMemory(
480       64 << 10, 0, kMetricsName);
481   base::GlobalHistogramAllocator* allocator =
482       base::GlobalHistogramAllocator::Get();
483   base::HistogramBase* histogram;
484 
485   // Create files starting with a timestamp a few minutes back.
486   base::Time base_time = base::Time::Now() - base::Minutes(10);
487 
488   // Create some files in an odd order. The files are "touched" back in time to
489   // ensure that each file has a later timestamp on disk than the previous one.
490   base::ScopedTempDir metrics_files;
491   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
492   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
493                          allocator, base_time);
494   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
495                          allocator, base_time);
496   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
497   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
498   histogram->Add(1);
499   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
500                          allocator, base_time + base::Minutes(1));
501 
502   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
503   histogram->Add(2);
504   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
505                          allocator, base_time + base::Minutes(2));
506 
507   histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
508   histogram->Add(3);
509   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
510                          allocator, base_time + base::Minutes(3));
511 
512   histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
513   histogram->Add(3);
514   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
515                          allocator, base_time + base::Minutes(4));
516 
517   base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
518                   base_time + base::Minutes(5), base_time + base::Minutes(5));
519 
520   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
521                          base_time + base::Minutes(6));
522 
523   // The global allocator has to be detached here so that no metrics created
524   // by code called below get stored in it as that would make for potential
525   // use-after-free operations if that code is called again.
526   base::GlobalHistogramAllocator::ReleaseForTesting();
527 
528   // Register the file and allow the "checker" task to run.
529   provider()->RegisterSource(FileMetricsProvider::Params(
530       metrics_files.GetPath(),
531       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
532       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
533 
534   // Record embedded snapshots via snapshot-manager.
535   std::vector<uint32_t> actual_order;
536   provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
537       [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
538   OnDidCreateMetricsLog();
539   task_environment()->RunUntilIdle();
540 
541   // Files could come out in the order: a1, c2, d4, b3. They are recognizable by
542   // the number of histograms contained within each. The "0" is the last merge
543   // done, which detects that there are no more files to merge.
544   EXPECT_THAT(actual_order, testing::ElementsAre(1, 2, 4, 3, 0));
545 
546   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
547   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
548   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
549   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
550   EXPECT_TRUE(
551       base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
552   EXPECT_TRUE(
553       base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
554   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
555 }
556 
TEST_P(FileMetricsProviderTest,AccessDirectoryWithInvalidFiles)557 TEST_P(FileMetricsProviderTest, AccessDirectoryWithInvalidFiles) {
558   ASSERT_FALSE(PathExists(metrics_file()));
559 
560   // Create files starting with a timestamp a few minutes back.
561   base::Time base_time = base::Time::Now() - base::Minutes(10);
562 
563   base::ScopedTempDir metrics_files;
564   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
565 
566   CreateMetricsFileWithHistograms(
567       metrics_files.GetPath().AppendASCII("h1.pma"),
568       base_time + base::Minutes(1), 1,
569       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
570         allocator->memory_allocator()->SetMemoryState(
571             base::PersistentMemoryAllocator::MEMORY_DELETED);
572       }));
573 
574   CreateMetricsFileWithHistograms(
575       metrics_files.GetPath().AppendASCII("h2.pma"),
576       base_time + base::Minutes(2), 2,
577       base::BindOnce(&WriteSystemProfileToAllocator));
578 
579   CreateMetricsFileWithHistograms(
580       metrics_files.GetPath().AppendASCII("h3.pma"),
581       base_time + base::Minutes(3), 3,
582       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
583         allocator->memory_allocator()->SetMemoryState(
584             base::PersistentMemoryAllocator::MEMORY_DELETED);
585       }));
586 
587   {
588     base::File empty(metrics_files.GetPath().AppendASCII("h4.pma"),
589                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
590   }
591   base::TouchFile(metrics_files.GetPath().AppendASCII("h4.pma"),
592                   base_time + base::Minutes(4), base_time + base::Minutes(4));
593 
594   // Register the file and allow the "checker" task to run.
595   provider()->RegisterSource(FileMetricsProvider::Params(
596       metrics_files.GetPath(),
597       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
598       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
599 
600   // No files yet.
601   EXPECT_EQ(0U, GetIndependentHistogramCount());
602   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
603   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
604   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
605   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
606 
607   // H1 should be skipped and H2 available.
608   OnDidCreateMetricsLog();
609   task_environment()->RunUntilIdle();
610   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
611   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
612   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
613   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
614 
615   // H2 should be read and the file deleted.
616   EXPECT_EQ(2U, GetIndependentHistogramCount());
617   task_environment()->RunUntilIdle();
618   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
619 
620   // Nothing else should be found but the last (valid but empty) file will
621   // stick around to be processed later (should it get expanded).
622   EXPECT_EQ(0U, GetIndependentHistogramCount());
623   task_environment()->RunUntilIdle();
624   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
625   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
626 }
627 
TEST_P(FileMetricsProviderTest,AccessTimeLimitedDirectory)628 TEST_P(FileMetricsProviderTest, AccessTimeLimitedDirectory) {
629   ASSERT_FALSE(PathExists(metrics_file()));
630 
631   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
632                                                         kMetricsName);
633   base::GlobalHistogramAllocator* allocator =
634       base::GlobalHistogramAllocator::Get();
635   base::HistogramBase* histogram;
636 
637   // Create one old file and one new file. Histogram names must be 2 characters
638   // (see HistogramFlattenerDeltaRecorder).
639   base::ScopedTempDir metrics_files;
640   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
641   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
642   histogram->Add(1);
643   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
644                          allocator, base::Time::Now() - base::Hours(1));
645 
646   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
647   histogram->Add(2);
648   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
649                          allocator, base::Time::Now());
650 
651   // The global allocator has to be detached here so that no metrics created
652   // by code called below get stored in it as that would make for potential
653   // use-after-free operations if that code is called again.
654   base::GlobalHistogramAllocator::ReleaseForTesting();
655 
656   // Register the file and allow the "checker" task to run.
657   FileMetricsProvider::Params params(
658       metrics_files.GetPath(),
659       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
660       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
661   params.max_age = base::Minutes(30);
662   provider()->RegisterSource(params);
663 
664   // Only b2, with 2 histograms, should be read.
665   OnDidCreateMetricsLog();
666   task_environment()->RunUntilIdle();
667   EXPECT_EQ(2U, GetSnapshotHistogramCount());
668   OnDidCreateMetricsLog();
669   task_environment()->RunUntilIdle();
670   EXPECT_EQ(0U, GetSnapshotHistogramCount());
671 
672   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
673   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
674 }
675 
TEST_P(FileMetricsProviderTest,AccessCountLimitedDirectory)676 TEST_P(FileMetricsProviderTest, AccessCountLimitedDirectory) {
677   ASSERT_FALSE(PathExists(metrics_file()));
678 
679   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
680                                                         kMetricsName);
681   base::GlobalHistogramAllocator* allocator =
682       base::GlobalHistogramAllocator::Get();
683   base::HistogramBase* histogram;
684 
685   // Create one old file and one new file. Histogram names must be 2 characters
686   // (see HistogramFlattenerDeltaRecorder).
687   base::ScopedTempDir metrics_files;
688   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
689   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
690   histogram->Add(1);
691   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
692                          allocator, base::Time::Now() - base::Hours(1));
693 
694   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
695   histogram->Add(2);
696   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
697                          allocator, base::Time::Now());
698 
699   // The global allocator has to be detached here so that no metrics created
700   // by code called below get stored in it as that would make for potential
701   // use-after-free operations if that code is called again.
702   base::GlobalHistogramAllocator::ReleaseForTesting();
703 
704   // Register the file and allow the "checker" task to run.
705   FileMetricsProvider::Params params(
706       metrics_files.GetPath(),
707       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
708       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
709   params.max_dir_files = 1;
710   provider()->RegisterSource(params);
711 
712   // Only b2, with 2 histograms, should be read.
713   OnDidCreateMetricsLog();
714   task_environment()->RunUntilIdle();
715   EXPECT_EQ(2U, GetSnapshotHistogramCount());
716   OnDidCreateMetricsLog();
717   task_environment()->RunUntilIdle();
718   EXPECT_EQ(0U, GetSnapshotHistogramCount());
719 
720   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
721   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
722 }
723 
TEST_P(FileMetricsProviderTest,AccessSizeLimitedDirectory)724 TEST_P(FileMetricsProviderTest, AccessSizeLimitedDirectory) {
725   // This only works with large files that are big enough to count.
726   if (!create_large_files_)
727     return;
728 
729   ASSERT_FALSE(PathExists(metrics_file()));
730 
731   size_t file_size_kib = 64;
732   base::GlobalHistogramAllocator::CreateWithLocalMemory(file_size_kib << 10, 0,
733                                                         kMetricsName);
734   base::GlobalHistogramAllocator* allocator =
735       base::GlobalHistogramAllocator::Get();
736   base::HistogramBase* histogram;
737 
738   // Create one old file and one new file. Histogram names must be 2 characters
739   // (see HistogramFlattenerDeltaRecorder).
740   base::ScopedTempDir metrics_files;
741   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
742   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
743   histogram->Add(1);
744   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
745                          allocator, base::Time::Now() - base::Hours(1));
746 
747   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
748   histogram->Add(2);
749   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
750                          allocator, base::Time::Now());
751 
752   // The global allocator has to be detached here so that no metrics created
753   // by code called below get stored in it as that would make for potential
754   // use-after-free operations if that code is called again.
755   base::GlobalHistogramAllocator::ReleaseForTesting();
756 
757   // Register the file and allow the "checker" task to run.
758   FileMetricsProvider::Params params(
759       metrics_files.GetPath(),
760       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
761       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
762   params.max_dir_kib = file_size_kib + 1;
763   provider()->RegisterSource(params);
764 
765   // Only b2, with 2 histograms, should be read.
766   OnDidCreateMetricsLog();
767   task_environment()->RunUntilIdle();
768   EXPECT_EQ(2U, GetSnapshotHistogramCount());
769   OnDidCreateMetricsLog();
770   task_environment()->RunUntilIdle();
771   EXPECT_EQ(0U, GetSnapshotHistogramCount());
772 
773   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
774   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
775 }
776 
TEST_P(FileMetricsProviderTest,AccessFilteredDirectory)777 TEST_P(FileMetricsProviderTest, AccessFilteredDirectory) {
778   ASSERT_FALSE(PathExists(metrics_file()));
779 
780   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
781                                                         kMetricsName);
782   base::GlobalHistogramAllocator* allocator =
783       base::GlobalHistogramAllocator::Get();
784   base::HistogramBase* histogram;
785 
786   // Create files starting with a timestamp a few minutes back.
787   base::Time base_time = base::Time::Now() - base::Minutes(10);
788 
789   // Create some files in an odd order. The files are "touched" back in time to
790   // ensure that each file has a later timestamp on disk than the previous one.
791   base::ScopedTempDir metrics_files;
792   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
793   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
794   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
795   histogram->Add(1);
796   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
797                          allocator, base_time + base::Minutes(1));
798 
799   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
800   histogram->Add(2);
801   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
802                          allocator, base_time + base::Minutes(2));
803 
804   histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
805   histogram->Add(3);
806   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
807                          allocator, base_time + base::Minutes(3));
808 
809   histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
810   histogram->Add(3);
811   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
812                          allocator, base_time + base::Minutes(4));
813 
814   base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
815                   base_time + base::Minutes(5), base_time + base::Minutes(5));
816 
817   // The global allocator has to be detached here so that no metrics created
818   // by code called below get stored in it as that would make for potential
819   // use-after-free operations if that code is called again.
820   base::GlobalHistogramAllocator::ReleaseForTesting();
821 
822   // Register the file and allow the "checker" task to run.
823   FileMetricsProvider::Params params(
824       metrics_files.GetPath(),
825       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
826       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
827   const FileMetricsProvider::FilterAction actions[] = {
828       FileMetricsProvider::FILTER_PROCESS_FILE,   // a1
829       FileMetricsProvider::FILTER_TRY_LATER,      // c2
830       FileMetricsProvider::FILTER_SKIP_FILE,      // d4
831       FileMetricsProvider::FILTER_PROCESS_FILE,   // b3
832       FileMetricsProvider::FILTER_PROCESS_FILE};  // c2 (again)
833   SetFilterActions(&params, actions, std::size(actions));
834   provider()->RegisterSource(params);
835 
836   // Record embedded snapshots via snapshot-manager.
837   std::vector<uint32_t> actual_order;
838   provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
839       [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
840   OnDidCreateMetricsLog();
841   task_environment()->RunUntilIdle();
842 
843   // Files could come out in the order: a1, b3, c2. They are recognizable by the
844   // number of histograms contained within each. The "0" is the last merge done,
845   // which detects that there are no more files to merge.
846   EXPECT_THAT(actual_order, testing::ElementsAre(1, 3, 2, 0));
847 
848   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
849   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
850   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
851   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
852 }
853 
TEST_P(FileMetricsProviderTest,AccessReadWriteMetrics)854 TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
855   // Create a global histogram allocator that maps to a file.
856   ASSERT_FALSE(PathExists(metrics_file()));
857   base::GlobalHistogramAllocator::CreateWithFile(
858       metrics_file(),
859       create_large_files_ ? kLargeFileSize : kSmallFileSize,
860       0, kMetricsName);
861   CreateGlobalHistograms(2);
862   ASSERT_TRUE(PathExists(metrics_file()));
863   base::HistogramBase* h0 = GetCreatedHistogram(0);
864   base::HistogramBase* h1 = GetCreatedHistogram(1);
865   DCHECK(h0);
866   DCHECK(h1);
867   base::GlobalHistogramAllocator::ReleaseForTesting();
868 
869   // Register the file and allow the "checker" task to run.
870   provider()->RegisterSource(FileMetricsProvider::Params(
871       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
872       FileMetricsProvider::ASSOCIATE_CURRENT_RUN));
873 
874   // Record embedded snapshots via snapshot-manager.
875   OnDidCreateMetricsLog();
876   task_environment()->RunUntilIdle();
877   EXPECT_EQ(2U, GetSnapshotHistogramCount());
878   EXPECT_TRUE(base::PathExists(metrics_file()));
879 
880   // Make sure a second call to the snapshot-recorder doesn't break anything.
881   OnDidCreateMetricsLog();
882   task_environment()->RunUntilIdle();
883   EXPECT_EQ(0U, GetSnapshotHistogramCount());
884   EXPECT_TRUE(base::PathExists(metrics_file()));
885 
886   // Change a histogram and ensure that it's counted.
887   h0->Add(0);
888   EXPECT_EQ(1U, GetSnapshotHistogramCount());
889   EXPECT_TRUE(base::PathExists(metrics_file()));
890 
891   // Change the other histogram and verify.
892   h1->Add(11);
893   EXPECT_EQ(1U, GetSnapshotHistogramCount());
894   EXPECT_TRUE(base::PathExists(metrics_file()));
895 }
896 
TEST_P(FileMetricsProviderTest,AccessInitialMetrics)897 TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
898   ASSERT_FALSE(PathExists(metrics_file()));
899   CreateMetricsFileWithHistograms(2);
900 
901   // Register the file and allow the "checker" task to run.
902   ASSERT_TRUE(PathExists(metrics_file()));
903   provider()->RegisterSource(FileMetricsProvider::Params(
904       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
905       FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName));
906 
907   // Record embedded snapshots via snapshot-manager.
908   ASSERT_TRUE(HasPreviousSessionData());
909   task_environment()->RunUntilIdle();
910   {
911     HistogramFlattenerDeltaRecorder flattener;
912     base::HistogramSnapshotManager snapshot_manager(&flattener);
913     RecordInitialHistogramSnapshots(&snapshot_manager);
914     EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
915   }
916   EXPECT_TRUE(base::PathExists(metrics_file()));
917   OnDidCreateMetricsLog();
918   task_environment()->RunUntilIdle();
919   EXPECT_FALSE(base::PathExists(metrics_file()));
920 
921   // A run for normal histograms should produce nothing.
922   CreateMetricsFileWithHistograms(2);
923   OnDidCreateMetricsLog();
924   task_environment()->RunUntilIdle();
925   EXPECT_EQ(0U, GetSnapshotHistogramCount());
926   EXPECT_TRUE(base::PathExists(metrics_file()));
927   OnDidCreateMetricsLog();
928   task_environment()->RunUntilIdle();
929   EXPECT_TRUE(base::PathExists(metrics_file()));
930 }
931 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithoutProfile)932 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithoutProfile) {
933   ASSERT_FALSE(PathExists(metrics_file()));
934   CreateMetricsFileWithHistograms(2);
935 
936   // Register the file and allow the "checker" task to run.
937   ASSERT_TRUE(PathExists(metrics_file()));
938   provider()->RegisterSource(FileMetricsProvider::Params(
939       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
940       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
941 
942   // Record embedded snapshots via snapshot-manager.
943   OnDidCreateMetricsLog();
944   task_environment()->RunUntilIdle();
945   {
946     HistogramFlattenerDeltaRecorder flattener;
947     base::HistogramSnapshotManager snapshot_manager(&flattener);
948     ChromeUserMetricsExtension uma_proto;
949 
950     // A read of metrics with internal profiles should return nothing.
951     EXPECT_FALSE(HasIndependentMetrics());
952     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
953   }
954   EXPECT_TRUE(base::PathExists(metrics_file()));
955   OnDidCreateMetricsLog();
956   task_environment()->RunUntilIdle();
957   EXPECT_FALSE(base::PathExists(metrics_file()));
958 }
959 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithProfile)960 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithProfile) {
961   ASSERT_FALSE(PathExists(metrics_file()));
962   CreateMetricsFileWithHistograms(
963       metrics_file(), base::Time::Now(), 2,
964       base::BindOnce(&WriteSystemProfileToAllocator));
965 
966   // Register the file and allow the "checker" task to run.
967   ASSERT_TRUE(PathExists(metrics_file()));
968   provider()->RegisterSource(FileMetricsProvider::Params(
969       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
970       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
971 
972   // Record embedded snapshots via snapshot-manager.
973   OnDidCreateMetricsLog();
974   task_environment()->RunUntilIdle();
975   {
976     HistogramFlattenerDeltaRecorder flattener;
977     base::HistogramSnapshotManager snapshot_manager(&flattener);
978     RecordInitialHistogramSnapshots(&snapshot_manager);
979     EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
980 
981     // A read of metrics with internal profiles should return one result, and
982     // the independent log generated should have the embedded system profile.
983     ChromeUserMetricsExtension uma_proto;
984     EXPECT_TRUE(HasIndependentMetrics());
985     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
986     ASSERT_TRUE(uma_proto.has_system_profile());
987     ASSERT_EQ(1, uma_proto.system_profile().field_trial_size());
988     EXPECT_EQ(123U, uma_proto.system_profile().field_trial(0).name_id());
989     EXPECT_EQ(456U, uma_proto.system_profile().field_trial(0).group_id());
990     EXPECT_EQ(789U, uma_proto.system_profile().session_hash());
991     EXPECT_FALSE(HasIndependentMetrics());
992     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
993   }
994   task_environment()->RunUntilIdle();
995   EXPECT_FALSE(base::PathExists(metrics_file()));
996 }
997 
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithoutProfile)998 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithoutProfile) {
999   ASSERT_FALSE(PathExists(metrics_file()));
1000   CreateMetricsFileWithHistograms(2);
1001 
1002   // Register the file and allow the "checker" task to run.
1003   ASSERT_TRUE(PathExists(metrics_file()));
1004   provider()->RegisterSource(FileMetricsProvider::Params(
1005       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1006       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1007       kMetricsName));
1008 
1009   // Record embedded snapshots via snapshot-manager.
1010   ASSERT_TRUE(HasPreviousSessionData());
1011   task_environment()->RunUntilIdle();
1012   {
1013     HistogramFlattenerDeltaRecorder flattener;
1014     base::HistogramSnapshotManager snapshot_manager(&flattener);
1015     RecordInitialHistogramSnapshots(&snapshot_manager);
1016     EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
1017 
1018     // A read of metrics with internal profiles should return nothing.
1019     ChromeUserMetricsExtension uma_proto;
1020     EXPECT_FALSE(HasIndependentMetrics());
1021     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1022   }
1023   EXPECT_TRUE(base::PathExists(metrics_file()));
1024   OnDidCreateMetricsLog();
1025   task_environment()->RunUntilIdle();
1026   EXPECT_FALSE(base::PathExists(metrics_file()));
1027 }
1028 
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithProfile)1029 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithProfile) {
1030   ASSERT_FALSE(PathExists(metrics_file()));
1031   CreateMetricsFileWithHistograms(
1032       metrics_file(), base::Time::Now(), 2,
1033       base::BindOnce(&WriteSystemProfileToAllocator));
1034 
1035   // Register the file and allow the "checker" task to run.
1036   ASSERT_TRUE(PathExists(metrics_file()));
1037   provider()->RegisterSource(FileMetricsProvider::Params(
1038       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1039       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1040       kMetricsName));
1041 
1042   // Record embedded snapshots via snapshot-manager.
1043   EXPECT_FALSE(HasPreviousSessionData());
1044   task_environment()->RunUntilIdle();
1045   {
1046     HistogramFlattenerDeltaRecorder flattener;
1047     base::HistogramSnapshotManager snapshot_manager(&flattener);
1048     RecordInitialHistogramSnapshots(&snapshot_manager);
1049     EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
1050 
1051     // A read of metrics with internal profiles should return one result.
1052     ChromeUserMetricsExtension uma_proto;
1053     EXPECT_TRUE(HasIndependentMetrics());
1054     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1055     EXPECT_FALSE(HasIndependentMetrics());
1056     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1057   }
1058   task_environment()->RunUntilIdle();
1059   EXPECT_FALSE(base::PathExists(metrics_file()));
1060 }
1061 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsFromDir)1062 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsFromDir) {
1063   const int file_count = 3;
1064   base::Time file_base_time = base::Time::Now();
1065   std::vector<base::FilePath> file_names;
1066   for (int i = 0; i < file_count; ++i) {
1067     CreateMetricsFileWithHistograms(
1068         metrics_file(), base::Time::Now(), 2,
1069         base::BindOnce(&WriteSystemProfileToAllocator));
1070     ASSERT_TRUE(PathExists(metrics_file()));
1071     char new_name[] = "hX";
1072     new_name[1] = '1' + i;
1073     base::FilePath file_name = temp_dir().AppendASCII(new_name).AddExtension(
1074         base::PersistentMemoryAllocator::kFileExtension);
1075     base::Time file_time = file_base_time - base::Minutes(file_count - i);
1076     base::TouchFile(metrics_file(), file_time, file_time);
1077     base::Move(metrics_file(), file_name);
1078     file_names.push_back(std::move(file_name));
1079   }
1080 
1081   // Register the file and allow the "checker" task to run.
1082   provider()->RegisterSource(FileMetricsProvider::Params(
1083       temp_dir(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
1084       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE));
1085 
1086   OnDidCreateMetricsLog();
1087   task_environment()->RunUntilIdle();
1088 
1089   // A read of metrics with internal profiles should return one result.
1090   HistogramFlattenerDeltaRecorder flattener;
1091   base::HistogramSnapshotManager snapshot_manager(&flattener);
1092   ChromeUserMetricsExtension uma_proto;
1093   for (int i = 0; i < file_count; ++i) {
1094     EXPECT_TRUE(HasIndependentMetrics()) << i;
1095     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager)) << i;
1096     task_environment()->RunUntilIdle();
1097   }
1098   EXPECT_FALSE(HasIndependentMetrics());
1099   EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1100 
1101   OnDidCreateMetricsLog();
1102   task_environment()->RunUntilIdle();
1103   for (const auto& file_name : file_names)
1104     EXPECT_FALSE(base::PathExists(file_name));
1105 }
1106 
TEST_P(FileMetricsProviderTest,RecordInitialHistogramSnapshotsStabilityHistograms)1107 TEST_P(FileMetricsProviderTest,
1108        RecordInitialHistogramSnapshotsStabilityHistograms) {
1109   // Create a metrics file with 2 non-stability histograms and 2 stability
1110   // histograms. Histogram names must be 2 characters (see
1111   // HistogramFlattenerDeltaRecorder).
1112   ASSERT_FALSE(PathExists(metrics_file()));
1113   base::GlobalHistogramAllocator::CreateWithLocalMemory(
1114       create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1115   base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1116       "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1117   h0->Add(0);
1118   base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1119       "h1", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1120   h1->Add(0);
1121   base::HistogramBase* h2 = base::Histogram::FactoryGet(
1122       "h2", 1, 100, 10,
1123       /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1124   h2->Add(0);
1125   base::HistogramBase* h3 = base::Histogram::FactoryGet(
1126       "h3", 1, 100, 10,
1127       /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1128   h3->Add(0);
1129   base::GlobalHistogramAllocator* histogram_allocator =
1130       base::GlobalHistogramAllocator::ReleaseForTesting();
1131   WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1132                          base::Time::Now());
1133   ASSERT_TRUE(PathExists(metrics_file()));
1134 
1135   // Register the file and allow the "checker" task to run.
1136   provider()->RegisterSource(FileMetricsProvider::Params(
1137       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1138       FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName));
1139   ASSERT_TRUE(HasPreviousSessionData());
1140   task_environment()->RunUntilIdle();
1141 
1142   // Record embedded snapshots via snapshot-manager.
1143   HistogramFlattenerDeltaRecorder flattener;
1144   base::HistogramSnapshotManager snapshot_manager(&flattener);
1145   RecordInitialHistogramSnapshots(&snapshot_manager);
1146 
1147   // Verify that only the stability histograms were snapshotted.
1148   EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1149               testing::ElementsAre("h0", "h2"));
1150 
1151   // The metrics file should eventually be deleted.
1152   EXPECT_TRUE(base::PathExists(metrics_file()));
1153   OnDidCreateMetricsLog();
1154   task_environment()->RunUntilIdle();
1155   EXPECT_FALSE(base::PathExists(metrics_file()));
1156 }
1157 
TEST_P(FileMetricsProviderTest,IndependentLogContainsUmaHistograms)1158 TEST_P(FileMetricsProviderTest, IndependentLogContainsUmaHistograms) {
1159   ASSERT_FALSE(PathExists(metrics_file()));
1160   // Create a metrics file with 2 UMA histograms and 2 non-UMA histograms.
1161   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
1162   base::GlobalHistogramAllocator::CreateWithLocalMemory(
1163       create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1164   base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1165       "h0", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1166   h0->Add(0);
1167   base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1168       "h1", /*flags=*/base::HistogramBase::Flags::kNoFlags);
1169   h1->Add(0);
1170   base::HistogramBase* h2 = base::Histogram::FactoryGet(
1171       "h2", 1, 100, 10,
1172       /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1173   h2->Add(0);
1174   base::HistogramBase* h3 = base::Histogram::FactoryGet(
1175       "h3", 1, 100, 10,
1176       /*flags=*/base::HistogramBase::Flags::kNoFlags);
1177   h3->Add(0);
1178   base::GlobalHistogramAllocator* histogram_allocator =
1179       base::GlobalHistogramAllocator::ReleaseForTesting();
1180   // Write a system profile so that an independent log can successfully be
1181   // created from the metrics file.
1182   WriteSystemProfileToAllocator(histogram_allocator);
1183   WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1184                          base::Time::Now());
1185   ASSERT_TRUE(PathExists(metrics_file()));
1186 
1187   // Register the file and allow the "checker" task to run.
1188   provider()->RegisterSource(FileMetricsProvider::Params(
1189       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1190       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1191   OnDidCreateMetricsLog();
1192   task_environment()->RunUntilIdle();
1193 
1194   // Verify that the independent log provided only contains UMA histograms (both
1195   // stability and non-stability).
1196   ChromeUserMetricsExtension uma_proto;
1197   HistogramFlattenerDeltaRecorder flattener;
1198   base::HistogramSnapshotManager snapshot_manager(&flattener);
1199   EXPECT_TRUE(HasIndependentMetrics());
1200   EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1201   EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1202               testing::ElementsAre("h0", "h2"));
1203 
1204   // The metrics file should eventually be deleted.
1205   task_environment()->RunUntilIdle();
1206   EXPECT_FALSE(base::PathExists(metrics_file()));
1207 }
1208 
1209 // Verifies that if the embedded system profile in the file does not contain
1210 // a client UUID, the generated independent log's client ID is not overwritten.
TEST_P(FileMetricsProviderTest,EmbeddedProfileWithoutClientUuid)1211 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithoutClientUuid) {
1212   ASSERT_FALSE(PathExists(metrics_file()));
1213   CreateMetricsFileWithHistograms(
1214       metrics_file(), base::Time::Now(), 2,
1215       base::BindOnce(&WriteSystemProfileToAllocator));
1216 
1217   // Register the file and allow the "checker" task to run.
1218   ASSERT_TRUE(PathExists(metrics_file()));
1219   provider()->RegisterSource(FileMetricsProvider::Params(
1220       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1221       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1222 
1223   // Record embedded snapshots via snapshot-manager.
1224   OnDidCreateMetricsLog();
1225   task_environment()->RunUntilIdle();
1226   {
1227     HistogramFlattenerDeltaRecorder flattener;
1228     base::HistogramSnapshotManager snapshot_manager(&flattener);
1229 
1230     // Since the embedded system profile has no client_uuid set (see
1231     // WriteSystemProfileToAllocator()), the client ID written in |uma_proto|
1232     // should be kept.
1233     ChromeUserMetricsExtension uma_proto;
1234     uma_proto.set_client_id(1);
1235     EXPECT_TRUE(HasIndependentMetrics());
1236     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1237     EXPECT_EQ(uma_proto.client_id(), 1U);
1238   }
1239   task_environment()->RunUntilIdle();
1240   EXPECT_FALSE(base::PathExists(metrics_file()));
1241 }
1242 
1243 // Verifies that if the embedded system profile in the file contains a client
1244 // UUID, it is used as the generated independent log's client ID.
TEST_P(FileMetricsProviderTest,EmbeddedProfileWithClientUuid)1245 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithClientUuid) {
1246   ASSERT_FALSE(PathExists(metrics_file()));
1247   static constexpr char kProfileClientUuid[] = "abc";
1248   CreateMetricsFileWithHistograms(
1249       metrics_file(), base::Time::Now(), 2,
1250       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
1251         metrics::SystemProfileProto profile_proto;
1252         profile_proto.set_client_uuid(kProfileClientUuid);
1253 
1254         metrics::PersistentSystemProfile persistent_profile;
1255         persistent_profile.RegisterPersistentAllocator(
1256             allocator->memory_allocator());
1257         persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
1258       }));
1259 
1260   // Register the file and allow the "checker" task to run.
1261   ASSERT_TRUE(PathExists(metrics_file()));
1262   provider()->RegisterSource(FileMetricsProvider::Params(
1263       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1264       FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
1265 
1266   // Record embedded snapshots via snapshot-manager.
1267   OnDidCreateMetricsLog();
1268   task_environment()->RunUntilIdle();
1269   {
1270     HistogramFlattenerDeltaRecorder flattener;
1271     base::HistogramSnapshotManager snapshot_manager(&flattener);
1272 
1273     // Since the embedded system profile contains a client_uuid, the client ID
1274     // in |uma_proto| should be overwritten.
1275     ChromeUserMetricsExtension uma_proto;
1276     uma_proto.set_client_id(1);
1277     EXPECT_TRUE(HasIndependentMetrics());
1278     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1279     EXPECT_NE(uma_proto.client_id(), 1U);
1280     EXPECT_EQ(uma_proto.client_id(), MetricsLog::Hash(kProfileClientUuid));
1281   }
1282   task_environment()->RunUntilIdle();
1283   EXPECT_FALSE(base::PathExists(metrics_file()));
1284 }
1285 
1286 }  // namespace metrics
1287