• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/metrics/persistent_histogram_allocator.h"
6 
7 #include "base/files/file.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/metrics/bucket_ranges.h"
13 #include "base/metrics/histogram.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/metrics/persistent_memory_allocator.h"
17 #include "base/metrics/statistics_recorder.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace base {
22 
23 class PersistentHistogramAllocatorTest : public testing::Test {
24  public:
25   PersistentHistogramAllocatorTest(const PersistentHistogramAllocatorTest&) =
26       delete;
27   PersistentHistogramAllocatorTest& operator=(
28       const PersistentHistogramAllocatorTest&) = delete;
29 
30  protected:
31   const int32_t kAllocatorMemorySize = 64 << 10;  // 64 KiB
32 
PersistentHistogramAllocatorTest()33   PersistentHistogramAllocatorTest()
34       : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) {
35     CreatePersistentHistogramAllocator();
36   }
~PersistentHistogramAllocatorTest()37   ~PersistentHistogramAllocatorTest() override {
38     DestroyPersistentHistogramAllocator();
39   }
40 
CreatePersistentHistogramAllocator()41   void CreatePersistentHistogramAllocator() {
42     allocator_memory_.reset(new char[kAllocatorMemorySize]);
43 
44     GlobalHistogramAllocator::ReleaseForTesting();
45     memset(allocator_memory_.get(), 0, kAllocatorMemorySize);
46     GlobalHistogramAllocator::CreateWithPersistentMemory(
47         allocator_memory_.get(), kAllocatorMemorySize, 0, 0,
48         "PersistentHistogramAllocatorTest");
49     allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
50   }
51 
DestroyPersistentHistogramAllocator()52   void DestroyPersistentHistogramAllocator() {
53     allocator_ = nullptr;
54     GlobalHistogramAllocator::ReleaseForTesting();
55   }
56 
57   std::unique_ptr<StatisticsRecorder> statistics_recorder_;
58   std::unique_ptr<char[]> allocator_memory_;
59   raw_ptr<PersistentMemoryAllocator> allocator_ = nullptr;
60 };
61 
TEST_F(PersistentHistogramAllocatorTest,CreateAndIterate)62 TEST_F(PersistentHistogramAllocatorTest, CreateAndIterate) {
63   PersistentMemoryAllocator::MemoryInfo meminfo0;
64   allocator_->GetMemoryInfo(&meminfo0);
65 
66   // Try basic construction
67   HistogramBase* histogram = Histogram::FactoryGet(
68       "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
69   EXPECT_TRUE(histogram);
70   histogram->CheckName("TestHistogram");
71   PersistentMemoryAllocator::MemoryInfo meminfo1;
72   allocator_->GetMemoryInfo(&meminfo1);
73   EXPECT_GT(meminfo0.free, meminfo1.free);
74 
75   HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
76       "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
77   EXPECT_TRUE(linear_histogram);
78   linear_histogram->CheckName("TestLinearHistogram");
79   PersistentMemoryAllocator::MemoryInfo meminfo2;
80   allocator_->GetMemoryInfo(&meminfo2);
81   EXPECT_GT(meminfo1.free, meminfo2.free);
82 
83   HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet(
84       "TestBooleanHistogram", HistogramBase::kIsPersistent);
85   EXPECT_TRUE(boolean_histogram);
86   boolean_histogram->CheckName("TestBooleanHistogram");
87   PersistentMemoryAllocator::MemoryInfo meminfo3;
88   allocator_->GetMemoryInfo(&meminfo3);
89   EXPECT_GT(meminfo2.free, meminfo3.free);
90 
91   std::vector<int> custom_ranges;
92   custom_ranges.push_back(1);
93   custom_ranges.push_back(5);
94   HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
95       "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent);
96   EXPECT_TRUE(custom_histogram);
97   custom_histogram->CheckName("TestCustomHistogram");
98   PersistentMemoryAllocator::MemoryInfo meminfo4;
99   allocator_->GetMemoryInfo(&meminfo4);
100   EXPECT_GT(meminfo3.free, meminfo4.free);
101 
102   PersistentMemoryAllocator::Iterator iter(allocator_);
103   uint32_t type;
104   EXPECT_NE(0U, iter.GetNext(&type));  // Histogram
105   EXPECT_NE(0U, iter.GetNext(&type));  // LinearHistogram
106   EXPECT_NE(0U, iter.GetNext(&type));  // BooleanHistogram
107   EXPECT_NE(0U, iter.GetNext(&type));  // CustomHistogram
108   EXPECT_EQ(0U, iter.GetNext(&type));
109 
110   // Create a second allocator and have it access the memory of the first.
111   std::unique_ptr<HistogramBase> recovered;
112   PersistentHistogramAllocator recovery(
113       std::make_unique<PersistentMemoryAllocator>(
114           allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false));
115   PersistentHistogramAllocator::Iterator histogram_iter(&recovery);
116 
117   recovered = histogram_iter.GetNext();
118   ASSERT_TRUE(recovered);
119   recovered->CheckName("TestHistogram");
120 
121   recovered = histogram_iter.GetNext();
122   ASSERT_TRUE(recovered);
123   recovered->CheckName("TestLinearHistogram");
124 
125   recovered = histogram_iter.GetNext();
126   ASSERT_TRUE(recovered);
127   recovered->CheckName("TestBooleanHistogram");
128 
129   recovered = histogram_iter.GetNext();
130   ASSERT_TRUE(recovered);
131   recovered->CheckName("TestCustomHistogram");
132 
133   recovered = histogram_iter.GetNext();
134   EXPECT_FALSE(recovered);
135 }
136 
TEST_F(PersistentHistogramAllocatorTest,ConstructPaths)137 TEST_F(PersistentHistogramAllocatorTest, ConstructPaths) {
138   const FilePath dir_path(FILE_PATH_LITERAL("foo/"));
139   const std::string dir_string =
140       dir_path.NormalizePathSeparators().AsUTF8Unsafe();
141 
142   FilePath path = GlobalHistogramAllocator::ConstructFilePath(dir_path, "bar");
143   EXPECT_EQ(dir_string + "bar.pma", path.AsUTF8Unsafe());
144 
145   std::string name;
146   Time stamp;
147   ProcessId pid;
148   EXPECT_FALSE(
149       GlobalHistogramAllocator::ParseFilePath(path, &name, nullptr, nullptr));
150   EXPECT_FALSE(
151       GlobalHistogramAllocator::ParseFilePath(path, nullptr, &stamp, nullptr));
152   EXPECT_FALSE(
153       GlobalHistogramAllocator::ParseFilePath(path, nullptr, nullptr, &pid));
154 
155   path = GlobalHistogramAllocator::ConstructFilePathForUploadDir(
156       dir_path, "bar", Time::FromTimeT(12345), 6789);
157   EXPECT_EQ(dir_string + "bar-3039-1A85.pma", path.AsUTF8Unsafe());
158   ASSERT_TRUE(
159       GlobalHistogramAllocator::ParseFilePath(path, &name, &stamp, &pid));
160   EXPECT_EQ(name, "bar");
161   EXPECT_EQ(Time::FromTimeT(12345), stamp);
162   EXPECT_EQ(static_cast<ProcessId>(6789), pid);
163 }
164 
TEST_F(PersistentHistogramAllocatorTest,CreateWithFile)165 TEST_F(PersistentHistogramAllocatorTest, CreateWithFile) {
166   const char temp_name[] = "CreateWithFileTest";
167   ScopedTempDir temp_dir;
168   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
169   FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
170   const size_t temp_size = 64 << 10;  // 64 KiB
171 
172   // Test creation of a new file.
173   DestroyPersistentHistogramAllocator();
174   GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name);
175   EXPECT_EQ(std::string(temp_name),
176             GlobalHistogramAllocator::Get()->memory_allocator()->Name());
177 
178   // Test re-open of a possibly-existing file.
179   DestroyPersistentHistogramAllocator();
180   GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, "");
181   EXPECT_EQ(std::string(temp_name),
182             GlobalHistogramAllocator::Get()->memory_allocator()->Name());
183 
184   // Test re-open of an known-existing file.
185   DestroyPersistentHistogramAllocator();
186   GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, "");
187   EXPECT_EQ(std::string(temp_name),
188             GlobalHistogramAllocator::Get()->memory_allocator()->Name());
189 
190   // Final release so file and temp-dir can be removed.
191   DestroyPersistentHistogramAllocator();
192 }
193 
TEST_F(PersistentHistogramAllocatorTest,CreateSpareFile)194 TEST_F(PersistentHistogramAllocatorTest, CreateSpareFile) {
195   const char temp_name[] = "CreateSpareFileTest.pma";
196   ScopedTempDir temp_dir;
197   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
198   FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
199   const size_t temp_size = 64 << 10;  // 64 KiB
200 
201   ASSERT_TRUE(GlobalHistogramAllocator::CreateSpareFile(temp_file, temp_size));
202 
203   File file(temp_file, File::FLAG_OPEN | File::FLAG_READ);
204   ASSERT_TRUE(file.IsValid());
205   EXPECT_EQ(static_cast<int64_t>(temp_size), file.GetLength());
206 
207   char buffer[256];
208   for (size_t pos = 0; pos < temp_size; pos += sizeof(buffer)) {
209     ASSERT_EQ(static_cast<int>(sizeof(buffer)),
210               file.ReadAtCurrentPos(buffer, sizeof(buffer)));
211     for (size_t i = 0; i < sizeof(buffer); ++i)
212       EXPECT_EQ(0, buffer[i]);
213   }
214 }
215 
TEST_F(PersistentHistogramAllocatorTest,StatisticsRecorderMerge)216 TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderMerge) {
217   const char LinearHistogramName[] = "SRTLinearHistogram";
218   const char SparseHistogramName[] = "SRTSparseHistogram";
219   const size_t global_sr_initial_histogram_count =
220       StatisticsRecorder::GetHistogramCount();
221   const size_t global_sr_initial_bucket_ranges_count =
222       StatisticsRecorder::GetBucketRanges().size();
223 
224   // Create a local StatisticsRecorder in which the newly created histogram
225   // will be recorded. The global allocator must be replaced after because the
226   // act of releasing will cause the active SR to forget about all histograms
227   // in the relased memory.
228   std::unique_ptr<StatisticsRecorder> local_sr =
229       StatisticsRecorder::CreateTemporaryForTesting();
230   EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount());
231   std::unique_ptr<GlobalHistogramAllocator> old_allocator =
232       GlobalHistogramAllocator::ReleaseForTesting();
233   GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
234   ASSERT_TRUE(GlobalHistogramAllocator::Get());
235 
236   // Create a linear histogram for merge testing.
237   HistogramBase* histogram1 =
238       LinearHistogram::FactoryGet(LinearHistogramName, 1, 10, 10, 0);
239   ASSERT_TRUE(histogram1);
240   EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount());
241   histogram1->Add(3);
242   histogram1->Add(1);
243   histogram1->Add(4);
244   histogram1->AddCount(1, 4);
245   histogram1->Add(6);
246 
247   // Create a sparse histogram for merge testing.
248   HistogramBase* histogram2 =
249       SparseHistogram::FactoryGet(SparseHistogramName, 0);
250   ASSERT_TRUE(histogram2);
251   EXPECT_EQ(2U, StatisticsRecorder::GetHistogramCount());
252   histogram2->Add(3);
253   histogram2->Add(1);
254   histogram2->Add(4);
255   histogram2->AddCount(1, 4);
256   histogram2->Add(6);
257 
258   // Destroy the local SR and ensure that we're back to the initial state and
259   // restore the global allocator. Histograms created in the local SR will
260   // become unmanaged.
261   std::unique_ptr<GlobalHistogramAllocator> new_allocator =
262       GlobalHistogramAllocator::ReleaseForTesting();
263   local_sr.reset();
264   EXPECT_EQ(global_sr_initial_histogram_count,
265             StatisticsRecorder::GetHistogramCount());
266   EXPECT_EQ(global_sr_initial_bucket_ranges_count,
267             StatisticsRecorder::GetBucketRanges().size());
268   GlobalHistogramAllocator::Set(std::move(old_allocator));
269 
270   // Create a "recovery" allocator using the same memory as the local one.
271   PersistentHistogramAllocator recovery1(
272       std::make_unique<PersistentMemoryAllocator>(
273           const_cast<void*>(new_allocator->memory_allocator()->data()),
274           new_allocator->memory_allocator()->size(), 0, 0, "", false));
275   PersistentHistogramAllocator::Iterator histogram_iter1(&recovery1);
276 
277   // Get the histograms that were created locally (and forgotten) and merge
278   // them into the global SR. New objects will be created.
279   std::unique_ptr<HistogramBase> recovered;
280   while (true) {
281     recovered = histogram_iter1.GetNext();
282     if (!recovered)
283       break;
284 
285     recovery1.MergeHistogramDeltaToStatisticsRecorder(recovered.get());
286     HistogramBase* found =
287         StatisticsRecorder::FindHistogram(recovered->histogram_name());
288     EXPECT_NE(recovered.get(), found);
289   }
290   EXPECT_EQ(global_sr_initial_histogram_count + 2,
291             StatisticsRecorder::GetHistogramCount());
292 
293   // Check the merged histograms for accuracy.
294   HistogramBase* found = StatisticsRecorder::FindHistogram(LinearHistogramName);
295   ASSERT_TRUE(found);
296   std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples();
297   EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
298   EXPECT_EQ(1, snapshot->GetCount(3));
299   EXPECT_EQ(5, snapshot->GetCount(1));
300   EXPECT_EQ(1, snapshot->GetCount(4));
301   EXPECT_EQ(1, snapshot->GetCount(6));
302 
303   found = StatisticsRecorder::FindHistogram(SparseHistogramName);
304   ASSERT_TRUE(found);
305   snapshot = found->SnapshotSamples();
306   EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
307   EXPECT_EQ(1, snapshot->GetCount(3));
308   EXPECT_EQ(5, snapshot->GetCount(1));
309   EXPECT_EQ(1, snapshot->GetCount(4));
310   EXPECT_EQ(1, snapshot->GetCount(6));
311 
312   // Verify that the LinearHistogram's BucketRanges was registered with the
313   // global SR since the recovery allocator does not specify a custom
314   // RangesManager.
315   ASSERT_EQ(global_sr_initial_bucket_ranges_count + 1,
316             StatisticsRecorder::GetBucketRanges().size());
317 
318   // Perform additional histogram increments.
319   histogram1->AddCount(1, 3);
320   histogram1->Add(6);
321   histogram2->AddCount(1, 3);
322   histogram2->Add(7);
323 
324   // Do another merge.
325   PersistentHistogramAllocator recovery2(
326       std::make_unique<PersistentMemoryAllocator>(
327           const_cast<void*>(new_allocator->memory_allocator()->data()),
328           new_allocator->memory_allocator()->size(), 0, 0, "", false));
329   PersistentHistogramAllocator::Iterator histogram_iter2(&recovery2);
330   while (true) {
331     recovered = histogram_iter2.GetNext();
332     if (!recovered)
333       break;
334     recovery2.MergeHistogramDeltaToStatisticsRecorder(recovered.get());
335   }
336   EXPECT_EQ(global_sr_initial_histogram_count + 2,
337             StatisticsRecorder::GetHistogramCount());
338 
339   // And verify.
340   found = StatisticsRecorder::FindHistogram(LinearHistogramName);
341   snapshot = found->SnapshotSamples();
342   EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
343   EXPECT_EQ(1, snapshot->GetCount(3));
344   EXPECT_EQ(8, snapshot->GetCount(1));
345   EXPECT_EQ(1, snapshot->GetCount(4));
346   EXPECT_EQ(2, snapshot->GetCount(6));
347 
348   found = StatisticsRecorder::FindHistogram(SparseHistogramName);
349   snapshot = found->SnapshotSamples();
350   EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
351   EXPECT_EQ(1, snapshot->GetCount(3));
352   EXPECT_EQ(8, snapshot->GetCount(1));
353   EXPECT_EQ(1, snapshot->GetCount(4));
354   EXPECT_EQ(1, snapshot->GetCount(6));
355   EXPECT_EQ(1, snapshot->GetCount(7));
356 }
357 
TEST_F(PersistentHistogramAllocatorTest,CustomRangesManager)358 TEST_F(PersistentHistogramAllocatorTest, CustomRangesManager) {
359   const char LinearHistogramName[] = "TestLinearHistogram";
360   const size_t global_sr_initial_bucket_ranges_count =
361       StatisticsRecorder::GetBucketRanges().size();
362 
363   // Create a local StatisticsRecorder in which the newly created histogram
364   // will be recorded. The global allocator must be replaced after because the
365   // act of releasing will cause the active SR to forget about all histograms
366   // in the released memory.
367   std::unique_ptr<StatisticsRecorder> local_sr =
368       StatisticsRecorder::CreateTemporaryForTesting();
369   EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount());
370   std::unique_ptr<GlobalHistogramAllocator> old_allocator =
371       GlobalHistogramAllocator::ReleaseForTesting();
372   GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
373   ASSERT_TRUE(GlobalHistogramAllocator::Get());
374 
375   // Create a linear histogram and verify it is registered with the local SR.
376   HistogramBase* histogram = LinearHistogram::FactoryGet(
377       LinearHistogramName, /*minimum=*/1, /*maximum=*/10, /*bucket_count=*/10,
378       /*flags=*/0);
379   ASSERT_TRUE(histogram);
380   EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount());
381   histogram->Add(1);
382 
383   // Destroy the local SR and ensure that we're back to the initial state and
384   // restore the global allocator. The histogram created in the local SR will
385   // become unmanaged.
386   std::unique_ptr<GlobalHistogramAllocator> new_allocator =
387       GlobalHistogramAllocator::ReleaseForTesting();
388   local_sr.reset();
389   EXPECT_EQ(global_sr_initial_bucket_ranges_count,
390             StatisticsRecorder::GetBucketRanges().size());
391   GlobalHistogramAllocator::Set(std::move(old_allocator));
392 
393   // Create a "recovery" allocator using the same memory as the local one.
394   PersistentHistogramAllocator recovery(
395       std::make_unique<PersistentMemoryAllocator>(
396           const_cast<void*>(new_allocator->memory_allocator()->data()),
397           new_allocator->memory_allocator()->size(), 0, 0, "", false));
398 
399   // Set a custom RangesManager for the recovery allocator so that the
400   // BucketRanges are not registered with the global SR.
401   RangesManager* ranges_manager = new RangesManager();
402   recovery.SetRangesManager(ranges_manager);
403   EXPECT_EQ(0U, ranges_manager->GetBucketRanges().size());
404 
405   // Get the histogram that was created locally (and forgotten).
406   PersistentHistogramAllocator::Iterator histogram_iter1(&recovery);
407   std::unique_ptr<HistogramBase> recovered = histogram_iter1.GetNext();
408   ASSERT_TRUE(recovered);
409 
410   // Verify that there are no more histograms.
411   ASSERT_FALSE(histogram_iter1.GetNext());
412 
413   // Expect that the histogram's BucketRanges was not registered with the global
414   // statistics recorder since the recovery allocator specifies a custom
415   // RangesManager.
416   EXPECT_EQ(global_sr_initial_bucket_ranges_count,
417             StatisticsRecorder::GetBucketRanges().size());
418 
419   EXPECT_EQ(1U, ranges_manager->GetBucketRanges().size());
420 }
421 
TEST_F(PersistentHistogramAllocatorTest,RangesDeDuplication)422 TEST_F(PersistentHistogramAllocatorTest, RangesDeDuplication) {
423   // This corresponds to the "ranges_ref" field of the PersistentHistogramData
424   // structure defined (privately) inside persistent_histogram_allocator.cc.
425   const int kRangesRefIndex = 5;
426 
427   // Create two histograms with the same ranges.
428   HistogramBase* histogram1 =
429       Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, 0);
430   HistogramBase* histogram2 =
431       Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, 0);
432   const uint32_t ranges_ref = static_cast<Histogram*>(histogram1)
433                                   ->bucket_ranges()
434                                   ->persistent_reference();
435   ASSERT_NE(0U, ranges_ref);
436   EXPECT_EQ(ranges_ref, static_cast<Histogram*>(histogram2)
437                             ->bucket_ranges()
438                             ->persistent_reference());
439 
440   // Make sure that the persistent data record is also correct. Two histograms
441   // will be fetched; other allocations are not "iterable".
442   PersistentMemoryAllocator::Iterator iter(allocator_);
443   uint32_t type;
444   uint32_t ref1 = iter.GetNext(&type);
445   uint32_t ref2 = iter.GetNext(&type);
446   EXPECT_EQ(0U, iter.GetNext(&type));
447   EXPECT_NE(0U, ref1);
448   EXPECT_NE(0U, ref2);
449   EXPECT_NE(ref1, ref2);
450 
451   uint32_t* data1 =
452       allocator_->GetAsArray<uint32_t>(ref1, 0, kRangesRefIndex + 1);
453   uint32_t* data2 =
454       allocator_->GetAsArray<uint32_t>(ref2, 0, kRangesRefIndex + 1);
455   EXPECT_EQ(ranges_ref, data1[kRangesRefIndex]);
456   EXPECT_EQ(ranges_ref, data2[kRangesRefIndex]);
457 }
458 
TEST_F(PersistentHistogramAllocatorTest,MovePersistentFile)459 TEST_F(PersistentHistogramAllocatorTest, MovePersistentFile) {
460   const char temp_name[] = "MovePersistentFileTest.pma";
461   ScopedTempDir temp_dir;
462   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
463   FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
464   const size_t temp_size = 64 << 10;  // 64 KiB
465 
466   // Initialize persistent histogram system with a known file path.
467   DestroyPersistentHistogramAllocator();
468   GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name);
469   GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
470   ASSERT_TRUE(allocator->HasPersistentLocation());
471   EXPECT_EQ(allocator->GetPersistentLocation(), temp_file);
472   EXPECT_TRUE(base::PathExists(temp_file));
473 
474   // Move the persistent file to a new directory.
475   ScopedTempDir new_temp_dir;
476   ASSERT_TRUE(new_temp_dir.CreateUniqueTempDir());
477   EXPECT_TRUE(allocator->MovePersistentFile(new_temp_dir.GetPath()));
478 
479   // Verify that the persistent file was correctly moved |new_temp_dir|.
480   FilePath new_temp_file = new_temp_dir.GetPath().AppendASCII(temp_name);
481   ASSERT_TRUE(allocator->HasPersistentLocation());
482   EXPECT_EQ(allocator->GetPersistentLocation(), new_temp_file);
483   EXPECT_TRUE(base::PathExists(new_temp_file));
484   EXPECT_FALSE(base::PathExists(temp_file));
485 
486   // Emit a histogram after moving the file.
487   const char kHistogramName[] = "MovePersistentFile.Test";
488   base::UmaHistogramBoolean(kHistogramName, true);
489 
490   // Release the allocator.
491   DestroyPersistentHistogramAllocator();
492 
493   // Open and read the file in order to verify that |kHistogramName| was written
494   // to it even after being moved.
495   base::File file(new_temp_file, base::File::FLAG_OPEN | base::File::FLAG_READ);
496   std::unique_ptr<char[]> data = std::make_unique<char[]>(temp_size);
497   EXPECT_EQ(file.Read(/*offset=*/0, data.get(), temp_size),
498             static_cast<int>(temp_size));
499 
500   // Create an allocator and iterator using the file's data.
501   PersistentHistogramAllocator new_file_allocator(
502       std::make_unique<PersistentMemoryAllocator>(data.get(), temp_size, 0, 0,
503                                                   "", false));
504   PersistentHistogramAllocator::Iterator it(&new_file_allocator);
505 
506   // Verify that |kHistogramName| is in the file.
507   std::unique_ptr<HistogramBase> histogram;
508   bool found_histogram = false;
509   while ((histogram = it.GetNext()) != nullptr) {
510     if (strcmp(kHistogramName, histogram->histogram_name()) == 0) {
511       found_histogram = true;
512       break;
513     }
514   }
515   EXPECT_TRUE(found_histogram);
516 }
517 
518 }  // namespace base
519