1 // Copyright 2017 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 "components/cronet/host_cache_persistence_manager.h"
6
7 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
8 #include "base/test/task_environment.h"
9 #include "base/values.h"
10 #include "components/prefs/pref_registry_simple.h"
11 #include "components/prefs/testing_pref_service.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/network_isolation_key.h"
15 #include "net/dns/host_cache.h"
16 #include "net/dns/public/dns_query_type.h"
17 #include "net/dns/public/host_resolver_source.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace cronet {
21
22 class HostCachePersistenceManagerTest : public testing::Test {
23 protected:
SetUp()24 void SetUp() override {
25 cache_ = std::make_unique<net::HostCache>(/*max_entries=*/1000);
26 pref_service_ = std::make_unique<TestingPrefServiceSimple>();
27 pref_service_->registry()->RegisterListPref(kPrefName);
28 }
29
MakePersistenceManager(base::TimeDelta delay)30 void MakePersistenceManager(base::TimeDelta delay) {
31 persistence_manager_ = std::make_unique<HostCachePersistenceManager>(
32 cache_.get(), pref_service_.get(), kPrefName, delay, nullptr);
33 }
34
35 // Sets an entry in the HostCache in order to trigger a pref write. The
36 // caller is responsible for making sure this is a change that will trigger
37 // a write, and the HostCache's interaction with its PersistenceDelegate is
38 // assumed to work (it's tested in net/dns/host_cache_unittest.cc).
WriteToCache(const std::string & host)39 void WriteToCache(const std::string& host) {
40 net::HostCache::Key key(host, net::DnsQueryType::UNSPECIFIED, 0,
41 net::HostResolverSource::ANY,
42 net::NetworkAnonymizationKey());
43 net::HostCache::Entry entry(net::OK, /*ip_endpoints=*/{}, /*aliases=*/{},
44 net::HostCache::Entry::SOURCE_UNKNOWN);
45 cache_->Set(key, entry, base::TimeTicks::Now(), base::Seconds(1));
46 }
47
48 // Reads the current value of the pref from the TestingPrefServiceSimple
49 // and deserializes it into a temporary new HostCache. Only checks the size,
50 // not the full contents, since the tests in this file are only intended
51 // to test that writes happen when they're supposed to, not serialization
52 // correctness.
CheckPref(size_t expected_size)53 void CheckPref(size_t expected_size) {
54 const base::Value* value = pref_service_->GetUserPref(kPrefName);
55 net::HostCache temp_cache(10);
56 if (value)
57 temp_cache.RestoreFromListValue(value->GetList());
58 ASSERT_EQ(expected_size, temp_cache.size());
59 }
60
61 // Generates a temporary HostCache with a few entries and uses it to
62 // initialize the value in prefs.
InitializePref()63 void InitializePref() {
64 net::HostCache temp_cache(10);
65
66 net::HostCache::Key key1("1.test", net::DnsQueryType::UNSPECIFIED, 0,
67 net::HostResolverSource::ANY,
68 net::NetworkAnonymizationKey());
69 net::HostCache::Key key2("2.test", net::DnsQueryType::UNSPECIFIED, 0,
70 net::HostResolverSource::ANY,
71 net::NetworkAnonymizationKey());
72 net::HostCache::Key key3("3.test", net::DnsQueryType::UNSPECIFIED, 0,
73 net::HostResolverSource::ANY,
74 net::NetworkAnonymizationKey());
75 net::HostCache::Entry entry(net::OK, /*ip_endpoints=*/{}, /*aliases=*/{},
76 net::HostCache::Entry::SOURCE_UNKNOWN);
77
78 temp_cache.Set(key1, entry, base::TimeTicks::Now(), base::Seconds(1));
79 temp_cache.Set(key2, entry, base::TimeTicks::Now(), base::Seconds(1));
80 temp_cache.Set(key3, entry, base::TimeTicks::Now(), base::Seconds(1));
81
82 base::Value::List list;
83 temp_cache.GetList(list, false /* include_stale */,
84 net::HostCache::SerializationType::kRestorable);
85 pref_service_->SetList(kPrefName, std::move(list));
86 }
87
88 static const char kPrefName[];
89
90 base::test::TaskEnvironment task_environment_;
91 base::ScopedMockTimeMessageLoopTaskRunner task_runner_;
92
93 // The HostCache and PrefService have to outlive the
94 // HostCachePersistenceManager.
95 std::unique_ptr<net::HostCache> cache_;
96 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
97 std::unique_ptr<HostCachePersistenceManager> persistence_manager_;
98 };
99
100 const char HostCachePersistenceManagerTest::kPrefName[] = "net.test";
101
102 // Make a single change to the HostCache and make sure that it's written
103 // when the timer expires. Then repeat.
TEST_F(HostCachePersistenceManagerTest,SeparateWrites)104 TEST_F(HostCachePersistenceManagerTest, SeparateWrites) {
105 MakePersistenceManager(base::Seconds(60));
106
107 WriteToCache("1.test");
108 task_runner_->FastForwardBy(base::Seconds(59));
109 CheckPref(0);
110 task_runner_->FastForwardBy(base::Seconds(1));
111 CheckPref(1);
112
113 WriteToCache("2.test");
114 task_runner_->FastForwardBy(base::Seconds(59));
115 CheckPref(1);
116 task_runner_->FastForwardBy(base::Seconds(1));
117 CheckPref(2);
118 }
119
120 // Write to the HostCache multiple times and make sure that all changes
121 // are written to prefs at the appropriate times.
TEST_F(HostCachePersistenceManagerTest,MultipleWrites)122 TEST_F(HostCachePersistenceManagerTest, MultipleWrites) {
123 MakePersistenceManager(base::Seconds(300));
124
125 WriteToCache("1.test");
126 WriteToCache("2.test");
127 task_runner_->FastForwardBy(base::Seconds(299));
128 CheckPref(0);
129 task_runner_->FastForwardBy(base::Seconds(1));
130 CheckPref(2);
131
132 WriteToCache("3.test");
133 WriteToCache("4.test");
134 task_runner_->FastForwardBy(base::Seconds(299));
135 CheckPref(2);
136 task_runner_->FastForwardBy(base::Seconds(1));
137 CheckPref(4);
138 }
139
140 // Make changes to the HostCache at different times and ensure that the writes
141 // to prefs are batched as expected.
TEST_F(HostCachePersistenceManagerTest,BatchedWrites)142 TEST_F(HostCachePersistenceManagerTest, BatchedWrites) {
143 MakePersistenceManager(base::Milliseconds(100));
144
145 WriteToCache("1.test");
146 task_runner_->FastForwardBy(base::Milliseconds(30));
147 WriteToCache("2.test");
148 task_runner_->FastForwardBy(base::Milliseconds(30));
149 WriteToCache("3.test");
150 CheckPref(0);
151 task_runner_->FastForwardBy(base::Milliseconds(40));
152 CheckPref(3);
153
154 // Add a delay in between batches.
155 task_runner_->FastForwardBy(base::Milliseconds(50));
156
157 WriteToCache("4.test");
158 task_runner_->FastForwardBy(base::Milliseconds(30));
159 WriteToCache("5.test");
160 task_runner_->FastForwardBy(base::Milliseconds(30));
161 WriteToCache("6.test");
162 CheckPref(3);
163 task_runner_->FastForwardBy(base::Milliseconds(40));
164 CheckPref(6);
165 }
166
167 // Set the pref before the HostCachePersistenceManager is created, and make
168 // sure it gets picked up by the HostCache.
TEST_F(HostCachePersistenceManagerTest,InitAfterPrefs)169 TEST_F(HostCachePersistenceManagerTest, InitAfterPrefs) {
170 CheckPref(0);
171 InitializePref();
172 CheckPref(3);
173
174 MakePersistenceManager(base::Seconds(1));
175 task_runner_->RunUntilIdle();
176 ASSERT_EQ(3u, cache_->size());
177 }
178
179 // Set the pref after the HostCachePersistenceManager is created, and make
180 // sure it gets picked up by the HostCache.
TEST_F(HostCachePersistenceManagerTest,InitBeforePrefs)181 TEST_F(HostCachePersistenceManagerTest, InitBeforePrefs) {
182 MakePersistenceManager(base::Seconds(1));
183 ASSERT_EQ(0u, cache_->size());
184
185 CheckPref(0);
186 InitializePref();
187 CheckPref(3);
188 ASSERT_EQ(3u, cache_->size());
189 }
190
191 } // namespace cronet
192