// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/nqe/network_qualities_prefs_manager.h" #include #include #include #include "base/macros.h" #include "base/run_loop.h" #include "base/sequence_checker.h" #include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/values.h" #include "net/base/network_change_notifier.h" #include "net/nqe/effective_connection_type.h" #include "net/nqe/network_id.h" #include "net/nqe/network_quality_estimator_test_util.h" #include "net/nqe/network_quality_store.h" #include "net/test/test_with_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace { class TestPrefDelegate : public NetworkQualitiesPrefsManager::PrefDelegate { public: TestPrefDelegate() : write_count_(0), read_count_(0), value_(new base::DictionaryValue) {} ~TestPrefDelegate() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); value_->Clear(); EXPECT_EQ(0U, value_->size()); } void SetDictionaryValue(const base::DictionaryValue& value) override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); write_count_++; value_.reset(value.DeepCopy()); ASSERT_EQ(value.size(), value_->size()); } std::unique_ptr GetDictionaryValue() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); read_count_++; return value_->CreateDeepCopy(); } size_t write_count() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return write_count_; } size_t read_count() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return read_count_; } private: // Number of times prefs were written and read, respectively.. size_t write_count_; size_t read_count_; // Current value of the prefs. std::unique_ptr value_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(TestPrefDelegate); }; using NetworkQualitiesPrefManager = TestWithTaskEnvironment; TEST_F(NetworkQualitiesPrefManager, Write) { // Force set the ECT to Slow 2G so that the ECT does not match the default // ECT for the current connection type. This forces the prefs to be written // for the current connection. std::map variation_params; variation_params["force_effective_connection_type"] = "Slow-2G"; TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr prefs_delegate(new TestPrefDelegate()); TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get(); NetworkQualitiesPrefsManager manager(std::move(prefs_delegate)); manager.InitializeOnNetworkThread(&estimator); base::RunLoop().RunUntilIdle(); // Prefs must be read at when NetworkQualitiesPrefsManager is constructed. EXPECT_EQ(2u, prefs_delegate_ptr->read_count()); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); // Network quality generated from the default observation must be written. base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(4u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality.. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(5u, prefs_delegate_ptr->write_count()); // Prefs should not be read again. EXPECT_EQ(2u, prefs_delegate_ptr->read_count()); manager.ShutdownOnPrefSequence(); } TEST_F(NetworkQualitiesPrefManager, WriteWhenMatchingExpectedECT) { // Force set the ECT to Slow 2G so that the ECT does not match the default // ECT for the current connection type. This forces the prefs to be written // for the current connection. std::map variation_params; variation_params["force_effective_connection_type"] = "Slow-2G"; TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr prefs_delegate(new TestPrefDelegate()); TestPrefDelegate* prefs_delegate_ptr = prefs_delegate.get(); NetworkQualitiesPrefsManager manager(std::move(prefs_delegate)); manager.InitializeOnNetworkThread(&estimator); base::RunLoop().RunUntilIdle(); // Prefs must be read at when NetworkQualitiesPrefsManager is constructed. EXPECT_EQ(2u, prefs_delegate_ptr->read_count()); const nqe::internal::NetworkID network_id( NetworkChangeNotifier::ConnectionType::CONNECTION_4G, "test", INT32_MIN); estimator.SimulateNetworkChange(network_id.type, network_id.id); EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); // Network quality generated from the default observation must be written. base::RunLoop().RunUntilIdle(); EXPECT_EQ(3u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(4u, prefs_delegate_ptr->write_count()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_3G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality.. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(5u, prefs_delegate_ptr->write_count()); // Prefs should not be read again. EXPECT_EQ(2u, prefs_delegate_ptr->read_count()); EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_3G, manager.ForceReadPrefsForTesting() .find(network_id) ->second.effective_connection_type()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_4G); estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); // Network Quality should be persisted to disk even if it matches the typical // quality of the network. See crbug.com/890859. EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().count(network_id)); EXPECT_EQ(6u, prefs_delegate_ptr->write_count()); manager.ShutdownOnPrefSequence(); } TEST_F(NetworkQualitiesPrefManager, WriteAndReadWithMultipleNetworkIDs) { static const size_t kMaxCacheSize = 20u; // Force set the ECT to Slow 2G so that the ECT does not match the default // ECT for the current connection type. This forces the prefs to be written // for the current connection. std::map variation_params; variation_params["force_effective_connection_type"] = "Slow-2G"; TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr prefs_delegate(new TestPrefDelegate()); NetworkQualitiesPrefsManager manager(std::move(prefs_delegate)); manager.InitializeOnNetworkThread(&estimator); base::RunLoop().RunUntilIdle(); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test"); EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); estimator.set_recent_effective_connection_type( EFFECTIVE_CONNECTION_TYPE_SLOW_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); // Verify that the observer was notified, and the updated network quality was // written to the prefs. EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); // Change the network ID. for (size_t i = 0; i < kMaxCacheSize; ++i) { estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test" + base::NumberToString(i)); estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(std::min(i + 3, kMaxCacheSize), manager.ForceReadPrefsForTesting().size()); } std::map read_prefs = manager.ForceReadPrefsForTesting(); // Verify the contents of the prefs. size_t count_2g_entries = 0; for (std::map::const_iterator it = read_prefs.begin(); it != read_prefs.end(); ++it) { if (it->first.type == NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN) { continue; } EXPECT_EQ(0u, it->first.id.find("test", 0u)); EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_2G, it->first.type); EXPECT_EQ(EFFECTIVE_CONNECTION_TYPE_SLOW_2G, it->second.effective_connection_type()); ++count_2g_entries; } // At most one entry should be for the network with connection type // NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN. EXPECT_LE(kMaxCacheSize - 1, count_2g_entries); base::HistogramTester histogram_tester; estimator.OnPrefsRead(read_prefs); histogram_tester.ExpectUniqueSample("NQE.Prefs.ReadSize", kMaxCacheSize, 1); manager.ShutdownOnPrefSequence(); } // Verifies that the prefs are cleared correctly. TEST_F(NetworkQualitiesPrefManager, ClearPrefs) { // Force set the ECT to Slow 2G so that the ECT does not match the default // ECT for the current connection type. This forces the prefs to be written // for the current connection. std::map variation_params; variation_params["force_effective_connection_type"] = "Slow-2G"; TestNetworkQualityEstimator estimator(variation_params); std::unique_ptr prefs_delegate(new TestPrefDelegate()); NetworkQualitiesPrefsManager manager(std::move(prefs_delegate)); manager.InitializeOnNetworkThread(&estimator); base::RunLoop().RunUntilIdle(); estimator.SimulateNetworkChange( NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test"); EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); estimator.set_recent_effective_connection_type( EFFECTIVE_CONNECTION_TYPE_SLOW_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); // Verify that the observer was notified, and the updated network quality was // written to the prefs. EXPECT_EQ(2u, manager.ForceReadPrefsForTesting().size()); // Prefs must be completely cleared. manager.ClearPrefs(); EXPECT_EQ(0u, manager.ForceReadPrefsForTesting().size()); estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G); // Run a request so that effective connection type is recomputed, and // observers are notified of change in the network quality. estimator.RunOneRequest(); base::RunLoop().RunUntilIdle(); // Verify that the observer was notified, and the updated network quality was // written to the prefs. EXPECT_EQ(1u, manager.ForceReadPrefsForTesting().size()); manager.ShutdownOnPrefSequence(); } } // namespace } // namespace net