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 "net/nqe/network_qualities_prefs_manager.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <memory>
10
11 #include "base/run_loop.h"
12 #include "base/sequence_checker.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/test/metrics/histogram_tester.h"
15 #include "base/values.h"
16 #include "net/base/network_change_notifier.h"
17 #include "net/nqe/effective_connection_type.h"
18 #include "net/nqe/network_id.h"
19 #include "net/nqe/network_quality_estimator_test_util.h"
20 #include "net/nqe/network_quality_store.h"
21 #include "net/test/test_with_task_environment.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace net {
25
26 namespace {
27
28 class TestPrefDelegate : public NetworkQualitiesPrefsManager::PrefDelegate {
29 public:
30 TestPrefDelegate() = default;
31
32 TestPrefDelegate(const TestPrefDelegate&) = delete;
33 TestPrefDelegate& operator=(const TestPrefDelegate&) = delete;
34
~TestPrefDelegate()35 ~TestPrefDelegate() override {
36 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
37 }
38
SetDictionaryValue(const base::Value::Dict & dict)39 void SetDictionaryValue(const base::Value::Dict& dict) override {
40 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
41
42 write_count_++;
43 value_ = dict.Clone();
44 ASSERT_EQ(dict.size(), value_.size());
45 }
46
GetDictionaryValue()47 base::Value::Dict GetDictionaryValue() override {
48 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
49
50 read_count_++;
51 return value_.Clone();
52 }
53
write_count() const54 size_t write_count() const {
55 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56 return write_count_;
57 }
58
read_count() const59 size_t read_count() const {
60 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
61 return read_count_;
62 }
63
64 private:
65 // Number of times prefs were written and read, respectively..
66 size_t write_count_ = 0;
67 size_t read_count_ = 0;
68
69 // Current value of the prefs.
70 base::Value::Dict value_;
71
72 SEQUENCE_CHECKER(sequence_checker_);
73 };
74
75 using NetworkQualitiesPrefManager = TestWithTaskEnvironment;
76
TEST_F(NetworkQualitiesPrefManager,Write)77 TEST_F(NetworkQualitiesPrefManager, Write) {
78 // Force set the ECT to Slow 2G so that the ECT does not match the default
79 // ECT for the current connection type. This forces the prefs to be written
80 // for the current connection.
81 std::map<std::string, std::string> variation_params;
82 variation_params["force_effective_connection_type"] = "Slow-2G";
83 TestNetworkQualityEstimator estimator(variation_params);
84
85 auto prefs_delegate = std::make_unique<TestPrefDelegate>();
86 TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get();
87
88 NetworkQualitiesPrefsManager manager(std::move(prefs_delegate));
89 manager.InitializeOnNetworkThread(&estimator);
90 base::RunLoop().RunUntilIdle();
91
92 // Prefs must be read at when NetworkQualitiesPrefsManager is constructed.
93 EXPECT_EQ(2u, prefs_delegate_ptr->read_count());
94
95 estimator.SimulateNetworkChange(
96 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
97 EXPECT_EQ(3u, prefs_delegate_ptr->write_count());
98 // Network quality generated from the default observation must be written.
99 base::RunLoop().RunUntilIdle();
100 EXPECT_EQ(3u, prefs_delegate_ptr->write_count());
101
102 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
103 // Run a request so that effective connection type is recomputed, and
104 // observers are notified of change in the network quality.
105 estimator.RunOneRequest();
106 base::RunLoop().RunUntilIdle();
107 EXPECT_EQ(4u, prefs_delegate_ptr->write_count());
108
109 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
110 // Run a request so that effective connection type is recomputed, and
111 // observers are notified of change in the network quality..
112 estimator.RunOneRequest();
113 base::RunLoop().RunUntilIdle();
114 EXPECT_EQ(5u, prefs_delegate_ptr->write_count());
115
116 // Prefs should not be read again.
117 EXPECT_EQ(2u, prefs_delegate_ptr->read_count());
118
119 manager.ShutdownOnPrefSequence();
120 }
121
TEST_F(NetworkQualitiesPrefManager,WriteWhenMatchingExpectedECT)122 TEST_F(NetworkQualitiesPrefManager, WriteWhenMatchingExpectedECT) {
123 // Force set the ECT to Slow 2G so that the ECT does not match the default
124 // ECT for the current connection type. This forces the prefs to be written
125 // for the current connection.
126 std::map<std::string, std::string> variation_params;
127 variation_params["force_effective_connection_type"] = "Slow-2G";
128 TestNetworkQualityEstimator estimator(variation_params);
129
130 auto prefs_delegate = std::make_unique<TestPrefDelegate>();
131 TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get();
132
133 NetworkQualitiesPrefsManager manager(std::move(prefs_delegate));
134 manager.InitializeOnNetworkThread(&estimator);
135 base::RunLoop().RunUntilIdle();
136
137 // Prefs must be read at when NetworkQualitiesPrefsManager is constructed.
138 EXPECT_EQ(2u, prefs_delegate_ptr->read_count());
139
140 const nqe::internal::NetworkID network_id(
141 NetworkChangeNotifier::ConnectionType::CONNECTION_4G, "test", INT32_MIN);
142
143 estimator.SimulateNetworkChange(network_id.type, network_id.id);
144 EXPECT_EQ(3u, prefs_delegate_ptr->write_count());
145 // Network quality generated from the default observation must be written.
146 base::RunLoop().RunUntilIdle();
147 EXPECT_EQ(3u, prefs_delegate_ptr->write_count());
148
149 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
150 // Run a request so that effective connection type is recomputed, and
151 // observers are notified of change in the network quality.
152 estimator.RunOneRequest();
153 base::RunLoop().RunUntilIdle();
154 EXPECT_EQ(4u, prefs_delegate_ptr->write_count());
155
156 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G);
157 // Run a request so that effective connection type is recomputed, and
158 // observers are notified of change in the network quality..
159 estimator.RunOneRequest();
160 base::RunLoop().RunUntilIdle();
161 EXPECT_EQ(5u, prefs_delegate_ptr->write_count());
162
163 // Prefs should not be read again.
164 EXPECT_EQ(2u, prefs_delegate_ptr->read_count());
165
166 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
167 EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_3G,
168 manager.ForceReadPrefsForTesting()
169 .find(network_id)
170 ->second.effective_connection_type());
171
172 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_4G);
173 estimator.RunOneRequest();
174 base::RunLoop().RunUntilIdle();
175
176 // Network Quality should be persisted to disk even if it matches the typical
177 // quality of the network. See crbug.com/890859.
178 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
179 EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().count(network_id));
180 EXPECT_EQ(6u, prefs_delegate_ptr->write_count());
181
182 manager.ShutdownOnPrefSequence();
183 }
184
TEST_F(NetworkQualitiesPrefManager,WriteAndReadWithMultipleNetworkIDs)185 TEST_F(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) {
186 static const size_t kMaxCacheSize = 20u;
187
188 // Force set the ECT to Slow 2G so that the ECT does not match the default
189 // ECT for the current connection type. This forces the prefs to be written
190 // for the current connection.
191 std::map<std::string, std::string> variation_params;
192 variation_params["force_effective_connection_type"] = "Slow-2G";
193 TestNetworkQualityEstimator estimator(variation_params);
194
195 auto prefs_delegate = std::make_unique<TestPrefDelegate>();
196
197 NetworkQualitiesPrefsManager manager(std::move(prefs_delegate));
198 manager.InitializeOnNetworkThread(&estimator);
199 base::RunLoop().RunUntilIdle();
200
201 estimator.SimulateNetworkChange(
202 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
203
204 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
205
206 estimator.set_recent_effective_connection_type(
207 EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
208 // Run a request so that effective connection type is recomputed, and
209 // observers are notified of change in the network quality.
210 estimator.RunOneRequest();
211 base::RunLoop().RunUntilIdle();
212 // Verify that the observer was notified, and the updated network quality was
213 // written to the prefs.
214 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
215
216 // Change the network ID.
217 for (size_t i = 0; i < kMaxCacheSize; ++i) {
218 estimator.SimulateNetworkChange(
219 NetworkChangeNotifier::ConnectionType::CONNECTION_2G,
220 "test" + base::NumberToString(i));
221
222 estimator.RunOneRequest();
223 base::RunLoop().RunUntilIdle();
224
225 EXPECT_EQ(std::min(i + 3, kMaxCacheSize),
226 manager.ForceReadPrefsForTesting().size());
227 }
228
229 std::map<nqe::internal::NetworkID, nqe::internal::CachedNetworkQuality>
230 read_prefs = manager.ForceReadPrefsForTesting();
231
232 // Verify the contents of the prefs.
233 size_t count_2g_entries = 0;
234 for (std::map<nqe::internal::NetworkID,
235 nqe::internal::CachedNetworkQuality>::const_iterator it =
236 read_prefs.begin();
237 it != read_prefs.end(); ++it) {
238 if (it->first.type ==
239 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN) {
240 continue;
241 }
242 EXPECT_EQ(0u, it->first.id.find("test", 0u));
243 EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_2G,
244 it->first.type);
245 EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
246 it->second.effective_connection_type());
247 ++count_2g_entries;
248 }
249
250 // At most one entry should be for the network with connection type
251 // NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN.
252 EXPECT_LE(kMaxCacheSize - 1, count_2g_entries);
253
254 estimator.OnPrefsRead(read_prefs);
255
256 manager.ShutdownOnPrefSequence();
257 }
258
259 // Verifies that the prefs are cleared correctly.
TEST_F(NetworkQualitiesPrefManager,ClearPrefs)260 TEST_F(NetworkQualitiesPrefManager, ClearPrefs) {
261 // Force set the ECT to Slow 2G so that the ECT does not match the default
262 // ECT for the current connection type. This forces the prefs to be written
263 // for the current connection.
264 std::map<std::string, std::string> variation_params;
265 variation_params["force_effective_connection_type"] = "Slow-2G";
266 TestNetworkQualityEstimator estimator(variation_params);
267
268 auto prefs_delegate = std::make_unique<TestPrefDelegate>();
269
270 NetworkQualitiesPrefsManager manager(std::move(prefs_delegate));
271 manager.InitializeOnNetworkThread(&estimator);
272 base::RunLoop().RunUntilIdle();
273
274 estimator.SimulateNetworkChange(
275 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
276
277 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
278
279 estimator.set_recent_effective_connection_type(
280 EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
281 // Run a request so that effective connection type is recomputed, and
282 // observers are notified of change in the network quality.
283 estimator.RunOneRequest();
284 base::RunLoop().RunUntilIdle();
285 // Verify that the observer was notified, and the updated network quality was
286 // written to the prefs.
287 EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size());
288
289 // Prefs must be completely cleared.
290 manager.ClearPrefs();
291 EXPECT_EQ(0u, manager.ForceReadPrefsForTesting().size());
292 estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
293 // Run a request so that effective connection type is recomputed, and
294 // observers are notified of change in the network quality.
295 estimator.RunOneRequest();
296 base::RunLoop().RunUntilIdle();
297 // Verify that the observer was notified, and the updated network quality was
298 // written to the prefs.
299 EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size());
300 manager.ShutdownOnPrefSequence();
301 }
302
303 } // namespace
304
305 } // namespace net
306