Add support for detecting metered networks on Windows.
This change adds GetConnectionCost() to the NetworkChangeNotifier class.
The structure is modeled after the existing functions of the class. The
base class implements a basic best-effort guess that works on platforms
that can detect cellular versus non-cellular types, which is essentially
the same as how "metered" network checks exist today.
This change updates the NetworkChangeNotifierWin class to retrieve the
metered network status and register for updates from the OS. It also
creates an Observer class similar to the other existing ones to notify
other components when it changes.
It's important to note that NetworkChangeNotifierWin will only register
for updates from the OS once an Observer is connected. If there is no
observer connected and someone asks for the current connection cost it
will be retrieved from the OS at that time rather than using the cached
value.
Bug: 1143428
Change-Id: I6f03ae91869087c6ad72a7f5891df158815137d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2542047
Reviewed-by: Paul Jensen <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Reviewed-by: Tarun Bansal <[email protected]>
Commit-Queue: Cliff Smolinsky <[email protected]>
Cr-Commit-Position: refs/heads/master@{#844383}
diff --git a/net/base/network_change_notifier_unittest.cc b/net/base/network_change_notifier_unittest.cc
index b5c2d86..81b5b49 100644
--- a/net/base/network_change_notifier_unittest.cc
+++ b/net/base/network_change_notifier_unittest.cc
@@ -198,7 +198,7 @@
}
class NetworkChangeNotifierMockedTest : public TestWithTaskEnvironment {
- private:
+ protected:
test::ScopedMockNetworkChangeNotifier mock_notifier_;
};
@@ -226,4 +226,92 @@
NetworkChangeNotifier::RemoveDNSObserver(&observer);
}
+class TestConnectionCostObserver
+ : public NetworkChangeNotifier::ConnectionCostObserver {
+ public:
+ void OnConnectionCostChanged(
+ NetworkChangeNotifier::ConnectionCost cost) override {
+ cost_changed_inputs_.push_back(cost);
+ ++cost_changed_calls_;
+ }
+
+ int cost_changed_calls() const { return cost_changed_calls_; }
+ std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs()
+ const {
+ return cost_changed_inputs_;
+ }
+
+ private:
+ int cost_changed_calls_ = 0;
+ std::vector<NetworkChangeNotifier::ConnectionCost> cost_changed_inputs_;
+};
+
+TEST_F(NetworkChangeNotifierMockedTest, TriggerConnectionCostChange) {
+ TestConnectionCostObserver observer;
+ NetworkChangeNotifier::AddConnectionCostObserver(&observer);
+
+ ASSERT_EQ(0, observer.cost_changed_calls());
+
+ NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests(
+ NetworkChangeNotifier::CONNECTION_COST_METERED);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, observer.cost_changed_calls());
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_METERED,
+ observer.cost_changed_inputs()[0]);
+
+ NetworkChangeNotifier::RemoveConnectionCostObserver(&observer);
+ NetworkChangeNotifier::NotifyObserversOfConnectionCostChangeForTests(
+ NetworkChangeNotifier::CONNECTION_COST_UNMETERED);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, observer.cost_changed_calls());
+}
+
+TEST_F(NetworkChangeNotifierMockedTest, ConnectionCostDefaultsToCellular) {
+ mock_notifier_.mock_network_change_notifier()
+ ->SetUseDefaultConnectionCostImplementation(true);
+
+ mock_notifier_.mock_network_change_notifier()->SetConnectionType(
+ NetworkChangeNotifier::CONNECTION_4G);
+ EXPECT_TRUE(NetworkChangeNotifier::IsConnectionCellular(
+ NetworkChangeNotifier::GetConnectionType()));
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_METERED,
+ NetworkChangeNotifier::GetConnectionCost());
+
+ mock_notifier_.mock_network_change_notifier()->SetConnectionType(
+ NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_FALSE(NetworkChangeNotifier::IsConnectionCellular(
+ NetworkChangeNotifier::GetConnectionType()));
+ EXPECT_EQ(NetworkChangeNotifier::CONNECTION_COST_UNMETERED,
+ NetworkChangeNotifier::GetConnectionCost());
+}
+
+class NetworkChangeNotifierConnectionCostTest : public TestWithTaskEnvironment {
+ public:
+ void SetUp() override {
+ network_change_notifier_ = NetworkChangeNotifier::CreateIfNeeded();
+ }
+
+ private:
+ // Allows creating a new NetworkChangeNotifier. Must be created before
+ // |network_change_notifier_| and destroyed after it to avoid DCHECK failures.
+ NetworkChangeNotifier::DisableForTest disable_for_test_;
+ std::unique_ptr<NetworkChangeNotifier> network_change_notifier_;
+};
+
+TEST_F(NetworkChangeNotifierConnectionCostTest, GetConnectionCost) {
+ EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
+ NetworkChangeNotifier::GetConnectionCost());
+}
+
+TEST_F(NetworkChangeNotifierConnectionCostTest, AddObserver) {
+ TestConnectionCostObserver observer;
+ EXPECT_NO_FATAL_FAILURE(
+ NetworkChangeNotifier::AddConnectionCostObserver(&observer));
+ // RunUntilIdle because the secondary work resulting from adding an observer
+ // may be posted to a task queue.
+ base::RunLoop().RunUntilIdle();
+}
+
} // namespace net