1 // Copyright 2016 The Chromium Authors. All rights reserved.
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 "base/bind.h"
8 #include "base/callback.h"
9 #include "base/files/file_util.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/histogram_flattener.h"
14 #include "base/metrics/histogram_snapshot_manager.h"
15 #include "base/metrics/persistent_histogram_allocator.h"
16 #include "base/metrics/persistent_memory_allocator.h"
17 #include "base/metrics/sparse_histogram.h"
18 #include "base/metrics/statistics_recorder.h"
19 #include "base/stl_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/test/test_simple_task_runner.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "base/time/time.h"
25 #include "components/metrics/metrics_pref_names.h"
26 #include "components/metrics/persistent_system_profile.h"
27 #include "components/prefs/pref_registry_simple.h"
28 #include "components/prefs/testing_pref_service.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
31 #include "third_party/metrics_proto/system_profile.pb.h"
32
33 namespace {
34 const char kMetricsName[] = "TestMetrics";
35 const char kMetricsFilename[] = "file.metrics";
36 } // namespace
37
38 namespace metrics {
39
40 class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
41 public:
HistogramFlattenerDeltaRecorder()42 HistogramFlattenerDeltaRecorder() {}
43
RecordDelta(const base::HistogramBase & histogram,const base::HistogramSamples & snapshot)44 void RecordDelta(const base::HistogramBase& histogram,
45 const base::HistogramSamples& snapshot) override {
46 // Only remember locally created histograms; they have exactly 2 chars.
47 if (strlen(histogram.histogram_name()) == 2)
48 recorded_delta_histogram_names_.push_back(histogram.histogram_name());
49 }
50
GetRecordedDeltaHistogramNames()51 std::vector<std::string> GetRecordedDeltaHistogramNames() {
52 return recorded_delta_histogram_names_;
53 }
54
55 private:
56 std::vector<std::string> recorded_delta_histogram_names_;
57
58 DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder);
59 };
60
61
62 class FileMetricsProviderTest : public testing::TestWithParam<bool> {
63 protected:
64 const size_t kSmallFileSize = 64 << 10; // 64 KiB
65 const size_t kLargeFileSize = 2 << 20; // 2 MiB
66
67 enum : int { kMaxCreateHistograms = 10 };
68
FileMetricsProviderTest()69 FileMetricsProviderTest()
70 : create_large_files_(GetParam()),
71 task_runner_(new base::TestSimpleTaskRunner()),
72 thread_task_runner_handle_(task_runner_),
73 statistics_recorder_(
74 base::StatisticsRecorder::CreateTemporaryForTesting()),
75 prefs_(new TestingPrefServiceSimple) {
76 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
77 FileMetricsProvider::RegisterPrefs(prefs_->registry(), kMetricsName);
78 FileMetricsProvider::SetTaskRunnerForTesting(task_runner_);
79 }
80
~FileMetricsProviderTest()81 ~FileMetricsProviderTest() override {
82 // Clear out any final remaining tasks.
83 task_runner_->RunUntilIdle();
84 FileMetricsProvider::SetTaskRunnerForTesting(nullptr);
85 DCHECK_EQ(0U, filter_actions_remaining_);
86 // If a global histogram allocator exists at this point then it likely
87 // acquired histograms that will continue to point to the released
88 // memory and potentially cause use-after-free memory corruption.
89 DCHECK(!base::GlobalHistogramAllocator::Get());
90 }
91
prefs()92 TestingPrefServiceSimple* prefs() { return prefs_.get(); }
temp_dir()93 base::FilePath temp_dir() { return temp_dir_.GetPath(); }
metrics_file()94 base::FilePath metrics_file() {
95 return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
96 }
97
provider()98 FileMetricsProvider* provider() {
99 if (!provider_)
100 provider_.reset(new FileMetricsProvider(prefs()));
101 return provider_.get();
102 }
103
OnDidCreateMetricsLog()104 void OnDidCreateMetricsLog() {
105 provider()->OnDidCreateMetricsLog();
106 }
107
HasPreviousSessionData()108 bool HasPreviousSessionData() { return provider()->HasPreviousSessionData(); }
109
MergeHistogramDeltas()110 void MergeHistogramDeltas() {
111 provider()->MergeHistogramDeltas();
112 }
113
HasIndependentMetrics()114 bool HasIndependentMetrics() { return provider()->HasIndependentMetrics(); }
115
ProvideIndependentMetrics(ChromeUserMetricsExtension * uma_proto,base::HistogramSnapshotManager * snapshot_manager)116 bool ProvideIndependentMetrics(
117 ChromeUserMetricsExtension* uma_proto,
118 base::HistogramSnapshotManager* snapshot_manager) {
119 bool success = false;
120 bool success_set = false;
121 provider()->ProvideIndependentMetrics(
122 base::BindOnce(
123 [](bool* success_ptr, bool* set_ptr, bool s) {
124 *success_ptr = s;
125 *set_ptr = true;
126 },
127 &success, &success_set),
128 uma_proto, snapshot_manager);
129
130 RunTasks();
131 CHECK(success_set);
132 return success;
133 }
134
RecordInitialHistogramSnapshots(base::HistogramSnapshotManager * snapshot_manager)135 void RecordInitialHistogramSnapshots(
136 base::HistogramSnapshotManager* snapshot_manager) {
137 provider()->RecordInitialHistogramSnapshots(snapshot_manager);
138 }
139
GetSnapshotHistogramCount()140 size_t GetSnapshotHistogramCount() {
141 // Merge the data from the allocator into the StatisticsRecorder.
142 provider()->MergeHistogramDeltas();
143
144 // Flatten what is known to see what has changed since the last time.
145 HistogramFlattenerDeltaRecorder flattener;
146 base::HistogramSnapshotManager snapshot_manager(&flattener);
147 // "true" to the begin() includes histograms held in persistent storage.
148 base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
149 base::Histogram::kNoFlags,
150 &snapshot_manager);
151 return flattener.GetRecordedDeltaHistogramNames().size();
152 }
153
GetIndependentHistogramCount()154 size_t GetIndependentHistogramCount() {
155 HistogramFlattenerDeltaRecorder flattener;
156 base::HistogramSnapshotManager snapshot_manager(&flattener);
157 ChromeUserMetricsExtension uma_proto;
158 provider()->ProvideIndependentMetrics(base::BindOnce([](bool success) {}),
159 &uma_proto, &snapshot_manager);
160
161 RunTasks();
162 return flattener.GetRecordedDeltaHistogramNames().size();
163 }
164
CreateGlobalHistograms(int histogram_count)165 void CreateGlobalHistograms(int histogram_count) {
166 DCHECK_GT(kMaxCreateHistograms, histogram_count);
167
168 // Create both sparse and normal histograms in the allocator.
169 created_histograms_[0] = base::SparseHistogram::FactoryGet("h0", 0);
170 created_histograms_[0]->Add(0);
171 for (int i = 1; i < histogram_count; ++i) {
172 created_histograms_[i] = base::Histogram::FactoryGet(
173 base::StringPrintf("h%d", i), 1, 100, 10, 0);
174 created_histograms_[i]->Add(i);
175 }
176 }
177
RunTasks()178 void RunTasks() {
179 // Run pending tasks twice: Once for IPC calls, once for replies. Don't
180 // use RunUntilIdle() because that can do more work than desired.
181 task_runner_->RunPendingTasks();
182 task_runner_->RunPendingTasks();
183 }
184
WriteMetricsFile(const base::FilePath & path,base::PersistentHistogramAllocator * metrics)185 void WriteMetricsFile(const base::FilePath& path,
186 base::PersistentHistogramAllocator* metrics) {
187 base::File writer(path,
188 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
189 // Use DCHECK so the stack-trace will indicate where this was called.
190 DCHECK(writer.IsValid()) << path.value();
191 size_t file_size = create_large_files_ ? metrics->size() : metrics->used();
192 int written = writer.Write(0, (const char*)metrics->data(), file_size);
193 DCHECK_EQ(static_cast<int>(file_size), written);
194 }
195
WriteMetricsFileAtTime(const base::FilePath & path,base::PersistentHistogramAllocator * metrics,base::Time write_time)196 void WriteMetricsFileAtTime(const base::FilePath& path,
197 base::PersistentHistogramAllocator* metrics,
198 base::Time write_time) {
199 WriteMetricsFile(path, metrics);
200 base::TouchFile(path, write_time, write_time);
201 }
202
203 std::unique_ptr<base::PersistentHistogramAllocator>
CreateMetricsFileWithHistograms(const base::FilePath & file_path,base::Time write_time,int histogram_count,base::OnceCallback<void (base::PersistentHistogramAllocator *)> callback)204 CreateMetricsFileWithHistograms(
205 const base::FilePath& file_path,
206 base::Time write_time,
207 int histogram_count,
208 base::OnceCallback<void(base::PersistentHistogramAllocator*)> callback) {
209 base::GlobalHistogramAllocator::CreateWithLocalMemory(
210 create_large_files_ ? kLargeFileSize : kSmallFileSize,
211 0, kMetricsName);
212
213 CreateGlobalHistograms(histogram_count);
214
215 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
216 base::GlobalHistogramAllocator::ReleaseForTesting();
217 std::move(callback).Run(histogram_allocator.get());
218
219 WriteMetricsFileAtTime(file_path, histogram_allocator.get(), write_time);
220 return histogram_allocator;
221 }
222
223 std::unique_ptr<base::PersistentHistogramAllocator>
CreateMetricsFileWithHistograms(int histogram_count)224 CreateMetricsFileWithHistograms(int histogram_count) {
225 return CreateMetricsFileWithHistograms(
226 metrics_file(), base::Time::Now(), histogram_count,
227 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {}));
228 }
229
GetCreatedHistogram(int index)230 base::HistogramBase* GetCreatedHistogram(int index) {
231 DCHECK_GT(kMaxCreateHistograms, index);
232 return created_histograms_[index];
233 }
234
SetFilterActions(FileMetricsProvider::Params * params,const FileMetricsProvider::FilterAction * actions,size_t count)235 void SetFilterActions(FileMetricsProvider::Params* params,
236 const FileMetricsProvider::FilterAction* actions,
237 size_t count) {
238 filter_actions_ = actions;
239 filter_actions_remaining_ = count;
240 params->filter = base::BindRepeating(
241 &FileMetricsProviderTest::FilterSourcePath, base::Unretained(this));
242 }
243
244 const bool create_large_files_;
245
246 private:
FilterSourcePath(const base::FilePath & path)247 FileMetricsProvider::FilterAction FilterSourcePath(
248 const base::FilePath& path) {
249 DCHECK_LT(0U, filter_actions_remaining_);
250 --filter_actions_remaining_;
251 return *filter_actions_++;
252 }
253
254 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
255 base::ThreadTaskRunnerHandle thread_task_runner_handle_;
256
257 std::unique_ptr<base::StatisticsRecorder> statistics_recorder_;
258 base::ScopedTempDir temp_dir_;
259 std::unique_ptr<TestingPrefServiceSimple> prefs_;
260 std::unique_ptr<FileMetricsProvider> provider_;
261 base::HistogramBase* created_histograms_[kMaxCreateHistograms];
262
263 const FileMetricsProvider::FilterAction* filter_actions_ = nullptr;
264 size_t filter_actions_remaining_ = 0;
265
266 DISALLOW_COPY_AND_ASSIGN(FileMetricsProviderTest);
267 };
268
269 // Run all test cases with both small and large files.
270 INSTANTIATE_TEST_SUITE_P(SmallAndLargeFiles,
271 FileMetricsProviderTest,
272 testing::Bool());
273
TEST_P(FileMetricsProviderTest,AccessMetrics)274 TEST_P(FileMetricsProviderTest, AccessMetrics) {
275 ASSERT_FALSE(PathExists(metrics_file()));
276
277 base::Time metrics_time = base::Time::Now() - base::TimeDelta::FromMinutes(5);
278 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
279 CreateMetricsFileWithHistograms(2);
280 ASSERT_TRUE(PathExists(metrics_file()));
281 base::TouchFile(metrics_file(), metrics_time, metrics_time);
282
283 // Register the file and allow the "checker" task to run.
284 provider()->RegisterSource(FileMetricsProvider::Params(
285 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
286 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
287
288 // Record embedded snapshots via snapshot-manager.
289 OnDidCreateMetricsLog();
290 RunTasks();
291 EXPECT_EQ(2U, GetSnapshotHistogramCount());
292 EXPECT_FALSE(base::PathExists(metrics_file()));
293
294 // Make sure a second call to the snapshot-recorder doesn't break anything.
295 OnDidCreateMetricsLog();
296 RunTasks();
297 EXPECT_EQ(0U, GetSnapshotHistogramCount());
298
299 // File should have been deleted but recreate it to test behavior should
300 // the file not be deleteable by this process.
301 WriteMetricsFileAtTime(metrics_file(), histogram_allocator.get(),
302 metrics_time);
303
304 // Second full run on the same file should produce nothing.
305 OnDidCreateMetricsLog();
306 RunTasks();
307 EXPECT_EQ(0U, GetSnapshotHistogramCount());
308 EXPECT_FALSE(base::PathExists(metrics_file()));
309
310 // Recreate the file to indicate that it is "new" and must be recorded.
311 metrics_time = metrics_time + base::TimeDelta::FromMinutes(1);
312 WriteMetricsFileAtTime(metrics_file(), histogram_allocator.get(),
313 metrics_time);
314
315 // This run should again have "new" histograms.
316 OnDidCreateMetricsLog();
317 RunTasks();
318 EXPECT_EQ(2U, GetSnapshotHistogramCount());
319 EXPECT_FALSE(base::PathExists(metrics_file()));
320 }
321
TEST_P(FileMetricsProviderTest,AccessTimeLimitedFile)322 TEST_P(FileMetricsProviderTest, AccessTimeLimitedFile) {
323 ASSERT_FALSE(PathExists(metrics_file()));
324
325 base::Time metrics_time = base::Time::Now() - base::TimeDelta::FromHours(5);
326 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
327 CreateMetricsFileWithHistograms(2);
328 ASSERT_TRUE(PathExists(metrics_file()));
329 base::TouchFile(metrics_file(), metrics_time, metrics_time);
330
331 // Register the file and allow the "checker" task to run.
332 FileMetricsProvider::Params params(
333 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
334 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
335 params.max_age = base::TimeDelta::FromHours(1);
336 provider()->RegisterSource(params);
337
338 // Attempt to access the file should return nothing.
339 OnDidCreateMetricsLog();
340 RunTasks();
341 EXPECT_EQ(0U, GetSnapshotHistogramCount());
342 EXPECT_FALSE(base::PathExists(metrics_file()));
343 }
344
TEST_P(FileMetricsProviderTest,FilterDelaysFile)345 TEST_P(FileMetricsProviderTest, FilterDelaysFile) {
346 ASSERT_FALSE(PathExists(metrics_file()));
347
348 base::Time now_time = base::Time::Now();
349 base::Time metrics_time = now_time - base::TimeDelta::FromMinutes(5);
350 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
351 CreateMetricsFileWithHistograms(2);
352 ASSERT_TRUE(PathExists(metrics_file()));
353 base::TouchFile(metrics_file(), metrics_time, metrics_time);
354 base::File::Info fileinfo;
355 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
356 EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
357
358 // Register the file and allow the "checker" task to run.
359 FileMetricsProvider::Params params(
360 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
361 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
362 const FileMetricsProvider::FilterAction actions[] = {
363 FileMetricsProvider::FILTER_TRY_LATER,
364 FileMetricsProvider::FILTER_PROCESS_FILE};
365 SetFilterActions(¶ms, actions, base::size(actions));
366 provider()->RegisterSource(params);
367
368 // Processing the file should touch it but yield no results. File timestamp
369 // accuracy is limited so compare the touched time to a couple seconds past.
370 OnDidCreateMetricsLog();
371 RunTasks();
372 EXPECT_EQ(0U, GetSnapshotHistogramCount());
373 EXPECT_TRUE(base::PathExists(metrics_file()));
374 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
375 EXPECT_LT(metrics_time, fileinfo.last_modified);
376 EXPECT_LE(now_time - base::TimeDelta::FromSeconds(2), fileinfo.last_modified);
377
378 // Second full run on the same file should process the file.
379 OnDidCreateMetricsLog();
380 RunTasks();
381 EXPECT_EQ(2U, GetSnapshotHistogramCount());
382 EXPECT_FALSE(base::PathExists(metrics_file()));
383 }
384
TEST_P(FileMetricsProviderTest,FilterSkipsFile)385 TEST_P(FileMetricsProviderTest, FilterSkipsFile) {
386 ASSERT_FALSE(PathExists(metrics_file()));
387
388 base::Time now_time = base::Time::Now();
389 base::Time metrics_time = now_time - base::TimeDelta::FromMinutes(5);
390 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
391 CreateMetricsFileWithHistograms(2);
392 ASSERT_TRUE(PathExists(metrics_file()));
393 base::TouchFile(metrics_file(), metrics_time, metrics_time);
394 base::File::Info fileinfo;
395 ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
396 EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
397
398 // Register the file and allow the "checker" task to run.
399 FileMetricsProvider::Params params(
400 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
401 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
402 const FileMetricsProvider::FilterAction actions[] = {
403 FileMetricsProvider::FILTER_SKIP_FILE};
404 SetFilterActions(¶ms, actions, base::size(actions));
405 provider()->RegisterSource(params);
406
407 // Processing the file should delete it.
408 OnDidCreateMetricsLog();
409 RunTasks();
410 EXPECT_EQ(0U, GetSnapshotHistogramCount());
411 EXPECT_FALSE(base::PathExists(metrics_file()));
412 }
413
TEST_P(FileMetricsProviderTest,AccessDirectory)414 TEST_P(FileMetricsProviderTest, AccessDirectory) {
415 ASSERT_FALSE(PathExists(metrics_file()));
416
417 base::GlobalHistogramAllocator::CreateWithLocalMemory(
418 64 << 10, 0, kMetricsName);
419 base::GlobalHistogramAllocator* allocator =
420 base::GlobalHistogramAllocator::Get();
421 base::HistogramBase* histogram;
422
423 // Create files starting with a timestamp a few minutes back.
424 base::Time base_time = base::Time::Now() - base::TimeDelta::FromMinutes(10);
425
426 // Create some files in an odd order. The files are "touched" back in time to
427 // ensure that each file has a later timestamp on disk than the previous one.
428 base::ScopedTempDir metrics_files;
429 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
430 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
431 allocator, base_time);
432 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
433 allocator, base_time);
434
435 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
436 histogram->Add(1);
437 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
438 allocator,
439 base_time + base::TimeDelta::FromMinutes(1));
440
441 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
442 histogram->Add(2);
443 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
444 allocator,
445 base_time + base::TimeDelta::FromMinutes(2));
446
447 histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
448 histogram->Add(3);
449 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
450 allocator,
451 base_time + base::TimeDelta::FromMinutes(3));
452
453 histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
454 histogram->Add(3);
455 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
456 allocator,
457 base_time + base::TimeDelta::FromMinutes(4));
458
459 base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
460 base_time + base::TimeDelta::FromMinutes(5),
461 base_time + base::TimeDelta::FromMinutes(5));
462
463 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
464 base_time + base::TimeDelta::FromMinutes(6));
465
466 // The global allocator has to be detached here so that no metrics created
467 // by code called below get stored in it as that would make for potential
468 // use-after-free operations if that code is called again.
469 base::GlobalHistogramAllocator::ReleaseForTesting();
470
471 // Register the file and allow the "checker" task to run.
472 provider()->RegisterSource(FileMetricsProvider::Params(
473 metrics_files.GetPath(),
474 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
475 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName));
476
477 // Files could come out in the order: a1, c2, d4, b3. They are recognizeable
478 // by the number of histograms contained within each.
479 const uint32_t expect_order[] = {1, 2, 4, 3, 0};
480 for (size_t i = 0; i < base::size(expect_order); ++i) {
481 // Record embedded snapshots via snapshot-manager.
482 OnDidCreateMetricsLog();
483 RunTasks();
484 EXPECT_EQ(expect_order[i], GetSnapshotHistogramCount()) << i;
485 }
486
487 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
488 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
489 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
490 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
491 EXPECT_TRUE(
492 base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
493 EXPECT_TRUE(
494 base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
495 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
496 }
497
TEST_P(FileMetricsProviderTest,AccessDirectoryWithInvalidFiles)498 TEST_P(FileMetricsProviderTest, AccessDirectoryWithInvalidFiles) {
499 ASSERT_FALSE(PathExists(metrics_file()));
500
501 // Create files starting with a timestamp a few minutes back.
502 base::Time base_time = base::Time::Now() - base::TimeDelta::FromMinutes(10);
503
504 base::ScopedTempDir metrics_files;
505 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
506
507 CreateMetricsFileWithHistograms(
508 metrics_files.GetPath().AppendASCII("h1.pma"),
509 base_time + base::TimeDelta::FromMinutes(1), 1,
510 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
511 allocator->memory_allocator()->SetMemoryState(
512 base::PersistentMemoryAllocator::MEMORY_DELETED);
513 }));
514
515 CreateMetricsFileWithHistograms(
516 metrics_files.GetPath().AppendASCII("h2.pma"),
517 base_time + base::TimeDelta::FromMinutes(2), 2,
518 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
519 SystemProfileProto profile_proto;
520 SystemProfileProto::FieldTrial* trial = profile_proto.add_field_trial();
521 trial->set_name_id(123);
522 trial->set_group_id(456);
523
524 PersistentSystemProfile persistent_profile;
525 persistent_profile.RegisterPersistentAllocator(
526 allocator->memory_allocator());
527 persistent_profile.SetSystemProfile(profile_proto, true);
528 }));
529
530 CreateMetricsFileWithHistograms(
531 metrics_files.GetPath().AppendASCII("h3.pma"),
532 base_time + base::TimeDelta::FromMinutes(3), 3,
533 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
534 allocator->memory_allocator()->SetMemoryState(
535 base::PersistentMemoryAllocator::MEMORY_DELETED);
536 }));
537
538 {
539 base::File empty(metrics_files.GetPath().AppendASCII("h4.pma"),
540 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
541 }
542 base::TouchFile(metrics_files.GetPath().AppendASCII("h4.pma"),
543 base_time + base::TimeDelta::FromMinutes(4),
544 base_time + base::TimeDelta::FromMinutes(4));
545
546 // Register the file and allow the "checker" task to run.
547 provider()->RegisterSource(FileMetricsProvider::Params(
548 metrics_files.GetPath(),
549 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
550 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
551
552 // No files yet.
553 EXPECT_EQ(0U, GetIndependentHistogramCount());
554 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
555 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
556 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
557 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
558
559 // H1 should be skipped and H2 available.
560 OnDidCreateMetricsLog();
561 RunTasks();
562 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h1.pma")));
563 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
564 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
565 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
566
567 // H2 should be read and the file deleted.
568 EXPECT_EQ(2U, GetIndependentHistogramCount());
569 RunTasks();
570 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h2.pma")));
571
572 // Nothing else should be found but the last (valid but empty) file will
573 // stick around to be processed later (should it get expanded).
574 EXPECT_EQ(0U, GetIndependentHistogramCount());
575 RunTasks();
576 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("h3.pma")));
577 EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("h4.pma")));
578 }
579
TEST_P(FileMetricsProviderTest,AccessTimeLimitedDirectory)580 TEST_P(FileMetricsProviderTest, AccessTimeLimitedDirectory) {
581 ASSERT_FALSE(PathExists(metrics_file()));
582
583 base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
584 kMetricsName);
585 base::GlobalHistogramAllocator* allocator =
586 base::GlobalHistogramAllocator::Get();
587 base::HistogramBase* histogram;
588
589 // Create one old file and one new file.
590 base::ScopedTempDir metrics_files;
591 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
592 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
593 histogram->Add(1);
594 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
595 allocator,
596 base::Time::Now() - base::TimeDelta::FromHours(1));
597
598 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
599 histogram->Add(2);
600 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
601 allocator, base::Time::Now());
602
603 // The global allocator has to be detached here so that no metrics created
604 // by code called below get stored in it as that would make for potential
605 // use-after-free operations if that code is called again.
606 base::GlobalHistogramAllocator::ReleaseForTesting();
607
608 // Register the file and allow the "checker" task to run.
609 FileMetricsProvider::Params params(
610 metrics_files.GetPath(),
611 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
612 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
613 params.max_age = base::TimeDelta::FromMinutes(30);
614 provider()->RegisterSource(params);
615
616 // Only b2, with 2 histograms, should be read.
617 OnDidCreateMetricsLog();
618 RunTasks();
619 EXPECT_EQ(2U, GetSnapshotHistogramCount());
620 OnDidCreateMetricsLog();
621 RunTasks();
622 EXPECT_EQ(0U, GetSnapshotHistogramCount());
623
624 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
625 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
626 }
627
TEST_P(FileMetricsProviderTest,AccessCountLimitedDirectory)628 TEST_P(FileMetricsProviderTest, AccessCountLimitedDirectory) {
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.
638 base::ScopedTempDir metrics_files;
639 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
640 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
641 histogram->Add(1);
642 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
643 allocator,
644 base::Time::Now() - base::TimeDelta::FromHours(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_dir_files = 1;
662 provider()->RegisterSource(params);
663
664 // Only b2, with 2 histograms, should be read.
665 OnDidCreateMetricsLog();
666 RunTasks();
667 EXPECT_EQ(2U, GetSnapshotHistogramCount());
668 OnDidCreateMetricsLog();
669 RunTasks();
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,AccessSizeLimitedDirectory)676 TEST_P(FileMetricsProviderTest, AccessSizeLimitedDirectory) {
677 // This only works with large files that are big enough to count.
678 if (!create_large_files_)
679 return;
680
681 ASSERT_FALSE(PathExists(metrics_file()));
682
683 size_t file_size_kib = 64;
684 base::GlobalHistogramAllocator::CreateWithLocalMemory(file_size_kib << 10, 0,
685 kMetricsName);
686 base::GlobalHistogramAllocator* allocator =
687 base::GlobalHistogramAllocator::Get();
688 base::HistogramBase* histogram;
689
690 // Create one old file and one new file.
691 base::ScopedTempDir metrics_files;
692 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
693 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
694 histogram->Add(1);
695 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
696 allocator,
697 base::Time::Now() - base::TimeDelta::FromHours(1));
698
699 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
700 histogram->Add(2);
701 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
702 allocator, base::Time::Now());
703
704 // The global allocator has to be detached here so that no metrics created
705 // by code called below get stored in it as that would make for potential
706 // use-after-free operations if that code is called again.
707 base::GlobalHistogramAllocator::ReleaseForTesting();
708
709 // Register the file and allow the "checker" task to run.
710 FileMetricsProvider::Params params(
711 metrics_files.GetPath(),
712 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
713 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
714 params.max_dir_kib = file_size_kib + 1;
715 provider()->RegisterSource(params);
716
717 // Only b2, with 2 histograms, should be read.
718 OnDidCreateMetricsLog();
719 RunTasks();
720 EXPECT_EQ(2U, GetSnapshotHistogramCount());
721 OnDidCreateMetricsLog();
722 RunTasks();
723 EXPECT_EQ(0U, GetSnapshotHistogramCount());
724
725 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
726 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
727 }
728
TEST_P(FileMetricsProviderTest,AccessFilteredDirectory)729 TEST_P(FileMetricsProviderTest, AccessFilteredDirectory) {
730 ASSERT_FALSE(PathExists(metrics_file()));
731
732 base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
733 kMetricsName);
734 base::GlobalHistogramAllocator* allocator =
735 base::GlobalHistogramAllocator::Get();
736 base::HistogramBase* histogram;
737
738 // Create files starting with a timestamp a few minutes back.
739 base::Time base_time = base::Time::Now() - base::TimeDelta::FromMinutes(10);
740
741 // Create some files in an odd order. The files are "touched" back in time to
742 // ensure that each file has a later timestamp on disk than the previous one.
743 base::ScopedTempDir metrics_files;
744 EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
745
746 histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
747 histogram->Add(1);
748 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
749 allocator,
750 base_time + base::TimeDelta::FromMinutes(1));
751
752 histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
753 histogram->Add(2);
754 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
755 allocator,
756 base_time + base::TimeDelta::FromMinutes(2));
757
758 histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
759 histogram->Add(3);
760 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
761 allocator,
762 base_time + base::TimeDelta::FromMinutes(3));
763
764 histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
765 histogram->Add(3);
766 WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
767 allocator,
768 base_time + base::TimeDelta::FromMinutes(4));
769
770 base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
771 base_time + base::TimeDelta::FromMinutes(5),
772 base_time + base::TimeDelta::FromMinutes(5));
773
774 // The global allocator has to be detached here so that no metrics created
775 // by code called below get stored in it as that would make for potential
776 // use-after-free operations if that code is called again.
777 base::GlobalHistogramAllocator::ReleaseForTesting();
778
779 // Register the file and allow the "checker" task to run.
780 FileMetricsProvider::Params params(
781 metrics_files.GetPath(),
782 FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
783 FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
784 const FileMetricsProvider::FilterAction actions[] = {
785 FileMetricsProvider::FILTER_PROCESS_FILE, // a1
786 FileMetricsProvider::FILTER_TRY_LATER, // c2
787 FileMetricsProvider::FILTER_SKIP_FILE, // d4
788 FileMetricsProvider::FILTER_PROCESS_FILE, // b3
789 FileMetricsProvider::FILTER_PROCESS_FILE}; // c2 (again)
790 SetFilterActions(¶ms, actions, base::size(actions));
791 provider()->RegisterSource(params);
792
793 // Files could come out in the order: a1, b3, c2. They are recognizeable
794 // by the number of histograms contained within each.
795 const uint32_t expect_order[] = {1, 3, 2, 0};
796 for (size_t i = 0; i < base::size(expect_order); ++i) {
797 // Record embedded snapshots via snapshot-manager.
798 OnDidCreateMetricsLog();
799 RunTasks();
800 EXPECT_EQ(expect_order[i], GetSnapshotHistogramCount()) << i;
801 }
802
803 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
804 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
805 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
806 EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
807 }
808
TEST_P(FileMetricsProviderTest,AccessReadWriteMetrics)809 TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
810 // Create a global histogram allocator that maps to a file.
811 ASSERT_FALSE(PathExists(metrics_file()));
812 base::GlobalHistogramAllocator::CreateWithFile(
813 metrics_file(),
814 create_large_files_ ? kLargeFileSize : kSmallFileSize,
815 0, kMetricsName);
816 CreateGlobalHistograms(2);
817 ASSERT_TRUE(PathExists(metrics_file()));
818 base::HistogramBase* h0 = GetCreatedHistogram(0);
819 base::HistogramBase* h1 = GetCreatedHistogram(1);
820 DCHECK(h0);
821 DCHECK(h1);
822 std::unique_ptr<base::PersistentHistogramAllocator> histogram_allocator =
823 base::GlobalHistogramAllocator::ReleaseForTesting();
824
825 // Register the file and allow the "checker" task to run.
826 provider()->RegisterSource(FileMetricsProvider::Params(
827 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
828 FileMetricsProvider::ASSOCIATE_CURRENT_RUN));
829
830 // Record embedded snapshots via snapshot-manager.
831 OnDidCreateMetricsLog();
832 RunTasks();
833 EXPECT_EQ(2U, GetSnapshotHistogramCount());
834 EXPECT_TRUE(base::PathExists(metrics_file()));
835
836 // Make sure a second call to the snapshot-recorder doesn't break anything.
837 OnDidCreateMetricsLog();
838 RunTasks();
839 EXPECT_EQ(0U, GetSnapshotHistogramCount());
840 EXPECT_TRUE(base::PathExists(metrics_file()));
841
842 // Change a histogram and ensure that it's counted.
843 h0->Add(0);
844 EXPECT_EQ(1U, GetSnapshotHistogramCount());
845 EXPECT_TRUE(base::PathExists(metrics_file()));
846
847 // Change the other histogram and verify.
848 h1->Add(11);
849 EXPECT_EQ(1U, GetSnapshotHistogramCount());
850 EXPECT_TRUE(base::PathExists(metrics_file()));
851 }
852
TEST_P(FileMetricsProviderTest,AccessInitialMetrics)853 TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
854 ASSERT_FALSE(PathExists(metrics_file()));
855 CreateMetricsFileWithHistograms(2);
856
857 // Register the file and allow the "checker" task to run.
858 ASSERT_TRUE(PathExists(metrics_file()));
859 provider()->RegisterSource(FileMetricsProvider::Params(
860 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
861 FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName));
862
863 // Record embedded snapshots via snapshot-manager.
864 ASSERT_TRUE(HasPreviousSessionData());
865 RunTasks();
866 {
867 HistogramFlattenerDeltaRecorder flattener;
868 base::HistogramSnapshotManager snapshot_manager(&flattener);
869 RecordInitialHistogramSnapshots(&snapshot_manager);
870 EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
871 }
872 EXPECT_TRUE(base::PathExists(metrics_file()));
873 OnDidCreateMetricsLog();
874 RunTasks();
875 EXPECT_FALSE(base::PathExists(metrics_file()));
876
877 // A run for normal histograms should produce nothing.
878 CreateMetricsFileWithHistograms(2);
879 OnDidCreateMetricsLog();
880 RunTasks();
881 EXPECT_EQ(0U, GetSnapshotHistogramCount());
882 EXPECT_TRUE(base::PathExists(metrics_file()));
883 OnDidCreateMetricsLog();
884 RunTasks();
885 EXPECT_TRUE(base::PathExists(metrics_file()));
886 }
887
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithoutProfile)888 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithoutProfile) {
889 ASSERT_FALSE(PathExists(metrics_file()));
890 CreateMetricsFileWithHistograms(2);
891
892 // Register the file and allow the "checker" task to run.
893 ASSERT_TRUE(PathExists(metrics_file()));
894 provider()->RegisterSource(FileMetricsProvider::Params(
895 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
896 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
897
898 // Record embedded snapshots via snapshot-manager.
899 OnDidCreateMetricsLog();
900 RunTasks();
901 {
902 HistogramFlattenerDeltaRecorder flattener;
903 base::HistogramSnapshotManager snapshot_manager(&flattener);
904 ChromeUserMetricsExtension uma_proto;
905
906 // A read of metrics with internal profiles should return nothing.
907 EXPECT_FALSE(HasIndependentMetrics());
908 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
909 }
910 EXPECT_TRUE(base::PathExists(metrics_file()));
911 OnDidCreateMetricsLog();
912 RunTasks();
913 EXPECT_FALSE(base::PathExists(metrics_file()));
914 }
915
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithProfile)916 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithProfile) {
917 ASSERT_FALSE(PathExists(metrics_file()));
918 CreateMetricsFileWithHistograms(
919 metrics_file(), base::Time::Now(), 2,
920 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
921 SystemProfileProto profile_proto;
922 SystemProfileProto::FieldTrial* trial = profile_proto.add_field_trial();
923 trial->set_name_id(123);
924 trial->set_group_id(456);
925
926 PersistentSystemProfile persistent_profile;
927 persistent_profile.RegisterPersistentAllocator(
928 allocator->memory_allocator());
929 persistent_profile.SetSystemProfile(profile_proto, true);
930 }));
931
932 // Register the file and allow the "checker" task to run.
933 ASSERT_TRUE(PathExists(metrics_file()));
934 provider()->RegisterSource(FileMetricsProvider::Params(
935 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
936 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName));
937
938 // Record embedded snapshots via snapshot-manager.
939 OnDidCreateMetricsLog();
940 RunTasks();
941 {
942 HistogramFlattenerDeltaRecorder flattener;
943 base::HistogramSnapshotManager snapshot_manager(&flattener);
944 RecordInitialHistogramSnapshots(&snapshot_manager);
945 EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
946
947 // A read of metrics with internal profiles should return one result.
948 ChromeUserMetricsExtension uma_proto;
949 EXPECT_TRUE(HasIndependentMetrics());
950 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
951 EXPECT_FALSE(HasIndependentMetrics());
952 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
953 }
954 RunTasks();
955 EXPECT_FALSE(base::PathExists(metrics_file()));
956 }
957
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithoutProfile)958 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithoutProfile) {
959 ASSERT_FALSE(PathExists(metrics_file()));
960 CreateMetricsFileWithHistograms(2);
961
962 // Register the file and allow the "checker" task to run.
963 ASSERT_TRUE(PathExists(metrics_file()));
964 provider()->RegisterSource(FileMetricsProvider::Params(
965 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
966 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
967 kMetricsName));
968
969 // Record embedded snapshots via snapshot-manager.
970 ASSERT_TRUE(HasPreviousSessionData());
971 RunTasks();
972 {
973 HistogramFlattenerDeltaRecorder flattener;
974 base::HistogramSnapshotManager snapshot_manager(&flattener);
975 RecordInitialHistogramSnapshots(&snapshot_manager);
976 EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
977
978 // A read of metrics with internal profiles should return nothing.
979 ChromeUserMetricsExtension uma_proto;
980 EXPECT_FALSE(HasIndependentMetrics());
981 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
982 }
983 EXPECT_TRUE(base::PathExists(metrics_file()));
984 OnDidCreateMetricsLog();
985 RunTasks();
986 EXPECT_FALSE(base::PathExists(metrics_file()));
987 }
988
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithProfile)989 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithProfile) {
990 ASSERT_FALSE(PathExists(metrics_file()));
991 CreateMetricsFileWithHistograms(
992 metrics_file(), base::Time::Now(), 2,
993 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
994 SystemProfileProto profile_proto;
995 SystemProfileProto::FieldTrial* trial = profile_proto.add_field_trial();
996 trial->set_name_id(123);
997 trial->set_group_id(456);
998
999 PersistentSystemProfile persistent_profile;
1000 persistent_profile.RegisterPersistentAllocator(
1001 allocator->memory_allocator());
1002 persistent_profile.SetSystemProfile(profile_proto, true);
1003 }));
1004
1005 // Register the file and allow the "checker" task to run.
1006 ASSERT_TRUE(PathExists(metrics_file()));
1007 provider()->RegisterSource(FileMetricsProvider::Params(
1008 metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1009 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1010 kMetricsName));
1011
1012 // Record embedded snapshots via snapshot-manager.
1013 EXPECT_FALSE(HasPreviousSessionData());
1014 RunTasks();
1015 {
1016 HistogramFlattenerDeltaRecorder flattener;
1017 base::HistogramSnapshotManager snapshot_manager(&flattener);
1018 RecordInitialHistogramSnapshots(&snapshot_manager);
1019 EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
1020
1021 // A read of metrics with internal profiles should return one result.
1022 ChromeUserMetricsExtension uma_proto;
1023 EXPECT_TRUE(HasIndependentMetrics());
1024 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1025 EXPECT_FALSE(HasIndependentMetrics());
1026 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1027 }
1028 RunTasks();
1029 EXPECT_FALSE(base::PathExists(metrics_file()));
1030 }
1031
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsFromDir)1032 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsFromDir) {
1033 const int file_count = 3;
1034 base::Time file_base_time = base::Time::Now();
1035 std::vector<base::FilePath> file_names;
1036 for (int i = 0; i < file_count; ++i) {
1037 CreateMetricsFileWithHistograms(
1038 metrics_file(), base::Time::Now(), 2,
1039 base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
1040 SystemProfileProto profile_proto;
1041 SystemProfileProto::FieldTrial* trial =
1042 profile_proto.add_field_trial();
1043 trial->set_name_id(123);
1044 trial->set_group_id(456);
1045
1046 PersistentSystemProfile persistent_profile;
1047 persistent_profile.RegisterPersistentAllocator(
1048 allocator->memory_allocator());
1049 persistent_profile.SetSystemProfile(profile_proto, true);
1050 }));
1051 ASSERT_TRUE(PathExists(metrics_file()));
1052 char new_name[] = "hX";
1053 new_name[1] = '1' + i;
1054 base::FilePath file_name = temp_dir().AppendASCII(new_name).AddExtension(
1055 base::PersistentMemoryAllocator::kFileExtension);
1056 base::Time file_time =
1057 file_base_time - base::TimeDelta::FromMinutes(file_count - i);
1058 base::TouchFile(metrics_file(), file_time, file_time);
1059 base::Move(metrics_file(), file_name);
1060 file_names.push_back(std::move(file_name));
1061 }
1062
1063 // Register the file and allow the "checker" task to run.
1064 provider()->RegisterSource(FileMetricsProvider::Params(
1065 temp_dir(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
1066 FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE));
1067
1068 OnDidCreateMetricsLog();
1069 RunTasks();
1070
1071 // A read of metrics with internal profiles should return one result.
1072 HistogramFlattenerDeltaRecorder flattener;
1073 base::HistogramSnapshotManager snapshot_manager(&flattener);
1074 ChromeUserMetricsExtension uma_proto;
1075 for (int i = 0; i < file_count; ++i) {
1076 EXPECT_TRUE(HasIndependentMetrics()) << i;
1077 EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager)) << i;
1078 RunTasks();
1079 }
1080 EXPECT_FALSE(HasIndependentMetrics());
1081 EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1082
1083 OnDidCreateMetricsLog();
1084 RunTasks();
1085 for (const auto& file_name : file_names)
1086 EXPECT_FALSE(base::PathExists(file_name));
1087 }
1088
1089 } // namespace metrics
1090