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