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 |