| Index: base/prefs/json_pref_store_unittest.cc
|
| diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
|
| index ff68836014f65bcb780e8aac035224e79a61d655..728a57d3417fc4e5893c4226939f12ba1b5cc7e8 100644
|
| --- a/base/prefs/json_pref_store_unittest.cc
|
| +++ b/base/prefs/json_pref_store_unittest.cc
|
| @@ -7,15 +7,20 @@
|
| #include "base/bind.h"
|
| #include "base/files/file_util.h"
|
| #include "base/files/scoped_temp_dir.h"
|
| +#include "base/location.h"
|
| #include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "base/metrics/histogram_samples.h"
|
| +#include "base/metrics/statistics_recorder.h"
|
| #include "base/path_service.h"
|
| #include "base/prefs/pref_filter.h"
|
| #include "base/run_loop.h"
|
| +#include "base/single_thread_task_runner.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "base/test/simple_test_clock.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| #include "base/threading/thread.h"
|
| #include "base/values.h"
|
| @@ -27,6 +32,12 @@ namespace {
|
|
|
| const char kHomePage[] = "homepage";
|
|
|
| +// Set the time on the given SimpleTestClock to the given time in minutes.
|
| +void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
|
| + const int32_t kBaseTimeMins = 100;
|
| + clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
|
| +}
|
| +
|
| // A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
|
| // to the |prefs| until explicitly asked to release them.
|
| class InterceptingPrefFilter : public PrefFilter {
|
| @@ -97,7 +108,8 @@ class JsonPrefStoreTest : public testing::Test {
|
| void TearDown() override {
|
| // Make sure all pending tasks have been processed (e.g., deleting the
|
| // JsonPrefStore may post write tasks).
|
| - message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
|
| + message_loop_.task_runner()->PostTask(FROM_HERE,
|
| + MessageLoop::QuitWhenIdleClosure());
|
| message_loop_.Run();
|
| }
|
|
|
| @@ -107,6 +119,10 @@ class JsonPrefStoreTest : public testing::Test {
|
| base::FilePath data_dir_;
|
| // A message loop that we can use as the file thread message loop.
|
| MessageLoop message_loop_;
|
| +
|
| + private:
|
| + // Ensure histograms are reset for each test.
|
| + StatisticsRecorder statistics_recorder_;
|
| };
|
|
|
| // Test fallback behavior for a nonexistent file.
|
| @@ -114,9 +130,7 @@ TEST_F(JsonPrefStoreTest, NonExistentFile) {
|
| base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
|
| ASSERT_FALSE(PathExists(bogus_input_file));
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - bogus_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
| EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
|
| pref_store->ReadPrefs());
|
| EXPECT_FALSE(pref_store->ReadOnly());
|
| @@ -129,11 +143,9 @@ TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
|
| data_dir_.AppendASCII("read_alternate.txt");
|
| ASSERT_FALSE(PathExists(bogus_input_file));
|
| ASSERT_FALSE(PathExists(bogus_alternate_input_file));
|
| - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - bogus_input_file,
|
| - bogus_alternate_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store =
|
| + new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
|
| + message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
| EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
|
| pref_store->ReadPrefs());
|
| EXPECT_FALSE(pref_store->ReadOnly());
|
| @@ -144,10 +156,8 @@ TEST_F(JsonPrefStoreTest, InvalidFile) {
|
| base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
|
| base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
|
| ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
|
| - scoped_refptr<JsonPrefStore> pref_store =
|
| - new JsonPrefStore(invalid_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| + invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
| EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
|
| pref_store->ReadPrefs());
|
| EXPECT_FALSE(pref_store->ReadOnly());
|
| @@ -233,9 +243,7 @@ TEST_F(JsonPrefStoreTest, Basic) {
|
| base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
|
| ASSERT_TRUE(PathExists(input_file));
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
| ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
|
| EXPECT_FALSE(pref_store->ReadOnly());
|
| EXPECT_TRUE(pref_store->IsInitializationComplete());
|
| @@ -262,9 +270,7 @@ TEST_F(JsonPrefStoreTest, BasicAsync) {
|
| base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
|
| ASSERT_TRUE(PathExists(input_file));
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| {
|
| MockPrefStoreObserver mock_observer;
|
| @@ -301,9 +307,7 @@ TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
|
| FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
|
|
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - pref_file,
|
| - message_loop_.message_loop_proxy(),
|
| - scoped_ptr<PrefFilter>());
|
| + pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| // Set some keys with empty values.
|
| pref_store->SetValue("list", new base::ListValue);
|
| @@ -314,10 +318,8 @@ TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
|
| MessageLoop::current()->RunUntilIdle();
|
|
|
| // Reload.
|
| - pref_store = new JsonPrefStore(
|
| - pref_file,
|
| - message_loop_.message_loop_proxy(),
|
| - scoped_ptr<PrefFilter>());
|
| + pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
|
| + scoped_ptr<PrefFilter>());
|
| ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
|
| ASSERT_FALSE(pref_store->ReadOnly());
|
|
|
| @@ -335,9 +337,7 @@ TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
|
| FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
|
|
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - pref_file,
|
| - message_loop_.message_loop_proxy(),
|
| - scoped_ptr<PrefFilter>());
|
| + pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| base::DictionaryValue* dict = new base::DictionaryValue;
|
| dict->SetString("key", "value");
|
| @@ -355,9 +355,7 @@ TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
|
| base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt");
|
| ASSERT_FALSE(PathExists(bogus_input_file));
|
| scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - bogus_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
| MockPrefStoreObserver mock_observer;
|
| pref_store->AddObserver(&mock_observer);
|
|
|
| @@ -385,10 +383,8 @@ TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
|
| new InterceptingPrefFilter());
|
| InterceptingPrefFilter* raw_intercepting_pref_filter_ =
|
| intercepting_pref_filter.get();
|
| - scoped_refptr<JsonPrefStore> pref_store =
|
| - new JsonPrefStore(input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - intercepting_pref_filter.Pass());
|
| + scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| + input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
|
|
|
| ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
|
| pref_store->ReadPrefs());
|
| @@ -432,10 +428,8 @@ TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
|
| new InterceptingPrefFilter());
|
| InterceptingPrefFilter* raw_intercepting_pref_filter_ =
|
| intercepting_pref_filter.get();
|
| - scoped_refptr<JsonPrefStore> pref_store =
|
| - new JsonPrefStore(input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - intercepting_pref_filter.Pass());
|
| + scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| + input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
|
|
|
| MockPrefStoreObserver mock_observer;
|
| pref_store->AddObserver(&mock_observer);
|
| @@ -498,11 +492,9 @@ TEST_F(JsonPrefStoreTest, AlternateFile) {
|
| temp_dir_.path().AppendASCII("alternate.json");
|
| ASSERT_FALSE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - alternate_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store =
|
| + new JsonPrefStore(input_file, alternate_input_file,
|
| + message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| ASSERT_FALSE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| @@ -544,11 +536,9 @@ TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
|
| temp_dir_.path().AppendASCII("alternate.json");
|
| ASSERT_TRUE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - alternate_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store =
|
| + new JsonPrefStore(input_file, alternate_input_file,
|
| + message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| ASSERT_TRUE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| @@ -586,11 +576,9 @@ TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
|
| temp_dir_.path().AppendASCII("alternate.json");
|
| ASSERT_TRUE(PathExists(input_file));
|
| ASSERT_FALSE(PathExists(alternate_input_file));
|
| - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - alternate_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store =
|
| + new JsonPrefStore(input_file, alternate_input_file,
|
| + message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| ASSERT_TRUE(PathExists(input_file));
|
| ASSERT_FALSE(PathExists(alternate_input_file));
|
| @@ -628,11 +616,9 @@ TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
|
| temp_dir_.path().AppendASCII("alternate.json");
|
| ASSERT_FALSE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| - scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
|
| - input_file,
|
| - alternate_input_file,
|
| - message_loop_.message_loop_proxy().get(),
|
| - scoped_ptr<PrefFilter>());
|
| + scoped_refptr<JsonPrefStore> pref_store =
|
| + new JsonPrefStore(input_file, alternate_input_file,
|
| + message_loop_.task_runner(), scoped_ptr<PrefFilter>());
|
|
|
| ASSERT_FALSE(PathExists(input_file));
|
| ASSERT_TRUE(PathExists(alternate_input_file));
|
| @@ -671,4 +657,148 @@ TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
|
| pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
|
| }
|
|
|
| +TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
|
| + SimpleTestClock* test_clock = new SimpleTestClock;
|
| + SetCurrentTimeInMinutes(0, test_clock);
|
| + JsonPrefStore::WriteCountHistogram histogram(
|
| + base::TimeDelta::FromSeconds(10),
|
| + base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
|
| + scoped_ptr<base::Clock>(test_clock));
|
| + int32 report_interval =
|
| + JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
|
| +
|
| + histogram.RecordWriteOccured();
|
| +
|
| + SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
|
| + histogram.ReportOutstandingWrites();
|
| + scoped_ptr<HistogramSamples> samples =
|
| + histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(1, samples->GetCount(1));
|
| + ASSERT_EQ(1, samples->TotalCount());
|
| +
|
| + ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
|
| + histogram.GetHistogram()->histogram_name());
|
| + ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
|
| +}
|
| +
|
| +TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
|
| + SimpleTestClock* test_clock = new SimpleTestClock;
|
| + SetCurrentTimeInMinutes(0, test_clock);
|
| + JsonPrefStore::WriteCountHistogram histogram(
|
| + base::TimeDelta::FromSeconds(10),
|
| + base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
|
| + scoped_ptr<base::Clock>(test_clock));
|
| + int32 report_interval =
|
| + JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
|
| +
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| +
|
| + // Nothing should be recorded until the report period has elapsed.
|
| + scoped_ptr<HistogramSamples> samples =
|
| + histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(0, samples->TotalCount());
|
| +
|
| + SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| +
|
| + // Now the report period has elapsed.
|
| + samples = histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(1, samples->GetCount(3));
|
| + ASSERT_EQ(1, samples->TotalCount());
|
| +
|
| + // The last write won't be recorded because the second count period hasn't
|
| + // fully elapsed.
|
| + SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
|
| + histogram.ReportOutstandingWrites();
|
| +
|
| + samples = histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(1, samples->GetCount(3));
|
| + ASSERT_EQ(1, samples->TotalCount());
|
| +}
|
| +
|
| +TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
|
| + SimpleTestClock* test_clock = new SimpleTestClock;
|
| + SetCurrentTimeInMinutes(0, test_clock);
|
| + JsonPrefStore::WriteCountHistogram histogram(
|
| + base::TimeDelta::FromSeconds(10),
|
| + base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
|
| + scoped_ptr<base::Clock>(test_clock));
|
| + int32 report_interval =
|
| + JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
|
| +
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| +
|
| + // The last write won't be recorded because the second count period hasn't
|
| + // fully elapsed
|
| + SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
|
| + histogram.ReportOutstandingWrites();
|
| + scoped_ptr<HistogramSamples> samples =
|
| + histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(2, samples->GetCount(3));
|
| + ASSERT_EQ(1, samples->GetCount(2));
|
| + ASSERT_EQ(3, samples->TotalCount());
|
| +}
|
| +
|
| +TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
|
| + SimpleTestClock* test_clock = new SimpleTestClock;
|
| + SetCurrentTimeInMinutes(0, test_clock);
|
| + JsonPrefStore::WriteCountHistogram histogram(
|
| + base::TimeDelta::FromSeconds(10),
|
| + base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
|
| + scoped_ptr<base::Clock>(test_clock));
|
| + int32 report_interval =
|
| + JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
|
| +
|
| + // 1 write in the first period.
|
| + histogram.RecordWriteOccured();
|
| +
|
| + // No writes in the second and third periods.
|
| +
|
| + // 2 writes in the fourth period.
|
| + SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| +
|
| + // No writes in the fifth period.
|
| +
|
| + // 3 writes in the sixth period.
|
| + SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| + SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
|
| + histogram.RecordWriteOccured();
|
| +
|
| + SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
|
| + histogram.ReportOutstandingWrites();
|
| + scoped_ptr<HistogramSamples> samples =
|
| + histogram.GetHistogram()->SnapshotSamples();
|
| + ASSERT_EQ(3, samples->GetCount(0));
|
| + ASSERT_EQ(1, samples->GetCount(1));
|
| + ASSERT_EQ(1, samples->GetCount(2));
|
| + ASSERT_EQ(1, samples->GetCount(3));
|
| + ASSERT_EQ(6, samples->TotalCount());
|
| +}
|
| +
|
| } // namespace base
|
|
|