// Copyright (c) 2012 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. // See network_change_notifier_android.h for design explanations. #include "base/bind.h" #include "base/callback.h" #include "base/compiler_specific.h" #include "base/message_loop/message_loop.h" #include "net/android/network_change_notifier_android.h" #include "net/android/network_change_notifier_delegate_android.h" #include "net/base/network_change_notifier.h" #include "net/dns/dns_config_service.h" #include "net/dns/dns_protocol.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace { // Types of network changes. See similarly named functions in // NetworkChangeNotifier::NetworkObserver for descriptions. enum ChangeType { NONE, CONNECTED, SOON_TO_DISCONNECT, DISCONNECTED, MADE_DEFAULT, }; class NetworkChangeNotifierDelegateAndroidObserver : public NetworkChangeNotifierDelegateAndroid::Observer { public: typedef NetworkChangeNotifier::ConnectionType ConnectionType; typedef NetworkChangeNotifier::NetworkHandle NetworkHandle; typedef NetworkChangeNotifier::NetworkList NetworkList; NetworkChangeNotifierDelegateAndroidObserver() : type_notifications_count_(0), max_bandwidth_notifications_count_(0) {} // NetworkChangeNotifierDelegateAndroid::Observer: void OnConnectionTypeChanged() override { type_notifications_count_++; } void OnMaxBandwidthChanged( double max_bandwidth_mbps, net::NetworkChangeNotifier::ConnectionType type) override { max_bandwidth_notifications_count_++; } void OnNetworkConnected(NetworkHandle network) override {} void OnNetworkSoonToDisconnect(NetworkHandle network) override {} void OnNetworkDisconnected(NetworkHandle network) override {} void OnNetworkMadeDefault(NetworkHandle network) override {} int type_notifications_count() const { return type_notifications_count_; } int bandwidth_notifications_count() const { return max_bandwidth_notifications_count_; } private: int type_notifications_count_; int max_bandwidth_notifications_count_; }; class NetworkChangeNotifierObserver : public NetworkChangeNotifier::ConnectionTypeObserver { public: NetworkChangeNotifierObserver() : notifications_count_(0) {} // NetworkChangeNotifier::ConnectionTypeObserver: void OnConnectionTypeChanged( NetworkChangeNotifier::ConnectionType connection_type) override { notifications_count_++; } int notifications_count() const { return notifications_count_; } private: int notifications_count_; }; class NetworkChangeNotifierMaxBandwidthObserver : public NetworkChangeNotifier::MaxBandwidthObserver { public: // NetworkChangeNotifier::MaxBandwidthObserver: void OnMaxBandwidthChanged( double max_bandwidth_mbps, NetworkChangeNotifier::ConnectionType type) override { notifications_count_++; } int notifications_count() const { return notifications_count_; } private: int notifications_count_ = 0; }; class DNSChangeObserver : public NetworkChangeNotifier::DNSObserver { public: DNSChangeObserver() : change_notifications_count_(0), initial_notifications_count_(0) {} // NetworkChangeNotifier::DNSObserver: void OnDNSChanged() override { change_notifications_count_++; } void OnInitialDNSConfigRead() override { initial_notifications_count_++; base::MessageLoop::current()->QuitWhenIdle(); } int change_notifications_count() const { return change_notifications_count_; } int initial_notifications_count() const { return initial_notifications_count_; } private: int change_notifications_count_; int initial_notifications_count_; }; // A NetworkObserver used for verifying correct notifications are sent. class TestNetworkObserver : public NetworkChangeNotifier::NetworkObserver { public: TestNetworkObserver() { Clear(); } void ExpectChange(ChangeType change, NetworkChangeNotifier::NetworkHandle network) { EXPECT_EQ(last_change_type_, change); EXPECT_EQ(last_network_changed_, network); Clear(); } private: void Clear() { last_change_type_ = NONE; last_network_changed_ = NetworkChangeNotifier::kInvalidNetworkHandle; } // NetworkChangeNotifier::NetworkObserver implementation: void OnNetworkConnected( NetworkChangeNotifier::NetworkHandle network) override { ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); last_change_type_ = CONNECTED; last_network_changed_ = network; } void OnNetworkSoonToDisconnect( NetworkChangeNotifier::NetworkHandle network) override { ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); last_change_type_ = SOON_TO_DISCONNECT; last_network_changed_ = network; } void OnNetworkDisconnected( NetworkChangeNotifier::NetworkHandle network) override { ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); last_change_type_ = DISCONNECTED; last_network_changed_ = network; } void OnNetworkMadeDefault( NetworkChangeNotifier::NetworkHandle network) override { // Cannot test for Clear()ed state as we receive CONNECTED immediately prior // to MADE_DEFAULT. last_change_type_ = MADE_DEFAULT; last_network_changed_ = network; } ChangeType last_change_type_; NetworkChangeNotifier::NetworkHandle last_network_changed_; }; } // namespace class BaseNetworkChangeNotifierAndroidTest : public testing::Test { protected: typedef NetworkChangeNotifier::ConnectionType ConnectionType; ~BaseNetworkChangeNotifierAndroidTest() override {} void RunTest( const base::Callback& notifications_count_getter, const base::Callback& connection_type_getter) { EXPECT_EQ(0, notifications_count_getter.Run()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, connection_type_getter.Run()); // Changing from online to offline should trigger a notification. SetOffline(); EXPECT_EQ(1, notifications_count_getter.Run()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, connection_type_getter.Run()); // No notification should be triggered when the offline state hasn't // changed. SetOffline(); EXPECT_EQ(1, notifications_count_getter.Run()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, connection_type_getter.Run()); // Going from offline to online should trigger a notification. SetOnline(); EXPECT_EQ(2, notifications_count_getter.Run()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, connection_type_getter.Run()); } void SetOnline() { delegate_.SetOnline(); // Note that this is needed because base::ObserverListThreadSafe uses // PostTask(). base::MessageLoop::current()->RunUntilIdle(); } void SetOffline() { delegate_.SetOffline(); // See comment above. base::MessageLoop::current()->RunUntilIdle(); } void FakeMaxBandwidthChange(double max_bandwidth_mbps) { delegate_.FakeMaxBandwidthChanged(max_bandwidth_mbps); base::MessageLoop::current()->RunUntilIdle(); } void FakeNetworkChange(ChangeType change, NetworkChangeNotifier::NetworkHandle network, ConnectionType type) { switch (change) { case CONNECTED: delegate_.FakeNetworkConnected(network, type); break; case SOON_TO_DISCONNECT: delegate_.FakeNetworkSoonToBeDisconnected(network); break; case DISCONNECTED: delegate_.FakeNetworkDisconnected(network); break; case MADE_DEFAULT: delegate_.FakeDefaultNetwork(network, type); break; case NONE: NOTREACHED(); break; } // See comment above. base::MessageLoop::current()->RunUntilIdle(); } void FakeUpdateActiveNetworkList( NetworkChangeNotifier::NetworkList networks) { delegate_.FakeUpdateActiveNetworkList(networks); // See comment above. base::MessageLoop::current()->RunUntilIdle(); } NetworkChangeNotifierDelegateAndroid delegate_; }; // Tests that NetworkChangeNotifierDelegateAndroid is initialized with the // actual connection type rather than a hardcoded one (e.g. // CONNECTION_UNKNOWN). Initializing the connection type to CONNECTION_UNKNOWN // and relying on the first network change notification to set it correctly can // be problematic in case there is a long delay between the delegate's // construction and the notification. TEST_F(BaseNetworkChangeNotifierAndroidTest, DelegateIsInitializedWithCurrentConnectionType) { SetOffline(); ASSERT_EQ(NetworkChangeNotifier::CONNECTION_NONE, delegate_.GetCurrentConnectionType()); // Instantiate another delegate to validate that it uses the actual // connection type at construction. scoped_ptr other_delegate( new NetworkChangeNotifierDelegateAndroid()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, other_delegate->GetCurrentConnectionType()); // Toggle the global connectivity state and instantiate another delegate // again. SetOnline(); ASSERT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, delegate_.GetCurrentConnectionType()); other_delegate.reset(new NetworkChangeNotifierDelegateAndroid()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, other_delegate->GetCurrentConnectionType()); } class NetworkChangeNotifierAndroidTest : public BaseNetworkChangeNotifierAndroidTest { protected: void SetUp() override { IPAddressNumber dns_number; ASSERT_TRUE(ParseIPLiteralToNumber("8.8.8.8", &dns_number)); dns_config_.nameservers.push_back( IPEndPoint(dns_number, dns_protocol::kDefaultPort)); notifier_.reset(new NetworkChangeNotifierAndroid(&delegate_, &dns_config_)); NetworkChangeNotifier::AddConnectionTypeObserver( &connection_type_observer_); NetworkChangeNotifier::AddConnectionTypeObserver( &other_connection_type_observer_); NetworkChangeNotifier::AddMaxBandwidthObserver(&max_bandwidth_observer_); } void ForceNetworkHandlesSupportedForTesting() { notifier_->ForceNetworkHandlesSupportedForTesting(); } NetworkChangeNotifierObserver connection_type_observer_; NetworkChangeNotifierMaxBandwidthObserver max_bandwidth_observer_; NetworkChangeNotifierObserver other_connection_type_observer_; NetworkChangeNotifier::DisableForTest disable_for_test_; DnsConfig dns_config_; scoped_ptr notifier_; }; class NetworkChangeNotifierDelegateAndroidTest : public NetworkChangeNotifierAndroidTest { protected: NetworkChangeNotifierDelegateAndroidTest() { delegate_.AddObserver(&delegate_observer_); delegate_.AddObserver(&other_delegate_observer_); } ~NetworkChangeNotifierDelegateAndroidTest() override { delegate_.RemoveObserver(&delegate_observer_); delegate_.RemoveObserver(&other_delegate_observer_); } NetworkChangeNotifierDelegateAndroidObserver delegate_observer_; NetworkChangeNotifierDelegateAndroidObserver other_delegate_observer_; }; // Tests that the NetworkChangeNotifierDelegateAndroid's observers are notified. // A testing-only observer is used here for testing. In production the // delegate's observers are instances of NetworkChangeNotifierAndroid. TEST_F(NetworkChangeNotifierDelegateAndroidTest, DelegateObserverNotified) { // Test the logic with a single observer. RunTest(base::Bind(&NetworkChangeNotifierDelegateAndroidObserver:: type_notifications_count, base::Unretained(&delegate_observer_)), base::Bind( &NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionType, base::Unretained(&delegate_))); // Check that *all* the observers are notified. Both observers should have the // same state. EXPECT_EQ(delegate_observer_.type_notifications_count(), other_delegate_observer_.type_notifications_count()); } // When a NetworkChangeNotifierAndroid is observing a // NetworkChangeNotifierDelegateAndroid for network state changes, and the // NetworkChangeNotifierDelegateAndroid's connectivity state changes, the // NetworkChangeNotifierAndroid should reflect that state. TEST_F(NetworkChangeNotifierAndroidTest, NotificationsSentToNetworkChangeNotifierAndroid) { RunTest(base::Bind(&NetworkChangeNotifierObserver::notifications_count, base::Unretained(&connection_type_observer_)), base::Bind(&NetworkChangeNotifierAndroid::GetCurrentConnectionType, base::Unretained(notifier_.get()))); } // When a NetworkChangeNotifierAndroid's connection state changes, it should // notify all of its observers. TEST_F(NetworkChangeNotifierAndroidTest, NotificationsSentToClientsOfNetworkChangeNotifier) { RunTest( base::Bind( &NetworkChangeNotifierObserver::notifications_count, base::Unretained(&connection_type_observer_)), base::Bind(&NetworkChangeNotifier::GetConnectionType)); // Check that *all* the observers are notified. EXPECT_EQ(connection_type_observer_.notifications_count(), other_connection_type_observer_.notifications_count()); } TEST_F(NetworkChangeNotifierAndroidTest, MaxBandwidth) { SetOnline(); double max_bandwidth_mbps = 0.0; NetworkChangeNotifier::ConnectionType connection_type = NetworkChangeNotifier::CONNECTION_NONE; notifier_->GetMaxBandwidthAndConnectionType(&max_bandwidth_mbps, &connection_type); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, connection_type); EXPECT_EQ(std::numeric_limits::infinity(), max_bandwidth_mbps); SetOffline(); notifier_->GetMaxBandwidthAndConnectionType(&max_bandwidth_mbps, &connection_type); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, connection_type); EXPECT_EQ(0.0, max_bandwidth_mbps); } TEST_F(NetworkChangeNotifierDelegateAndroidTest, MaxBandwidthCallbackNotifier) { // The bandwidth notification should always be forwarded, even if the value // doesn't change (because the type might have changed). FakeMaxBandwidthChange(100.0); EXPECT_EQ(1, delegate_observer_.bandwidth_notifications_count()); EXPECT_EQ(1, max_bandwidth_observer_.notifications_count()); FakeMaxBandwidthChange(100.0); EXPECT_EQ(2, delegate_observer_.bandwidth_notifications_count()); EXPECT_EQ(2, max_bandwidth_observer_.notifications_count()); FakeMaxBandwidthChange(101.0); EXPECT_EQ(3, delegate_observer_.bandwidth_notifications_count()); EXPECT_EQ(3, max_bandwidth_observer_.notifications_count()); } TEST_F(NetworkChangeNotifierDelegateAndroidTest, MaxBandwidthNotifiedOnConnectionChange) { EXPECT_EQ(0, delegate_observer_.bandwidth_notifications_count()); SetOffline(); EXPECT_EQ(1, delegate_observer_.bandwidth_notifications_count()); SetOnline(); EXPECT_EQ(2, delegate_observer_.bandwidth_notifications_count()); SetOnline(); EXPECT_EQ(2, delegate_observer_.bandwidth_notifications_count()); } TEST_F(NetworkChangeNotifierAndroidTest, InitialSignal) { DNSChangeObserver dns_change_observer; NetworkChangeNotifier::AddDNSObserver(&dns_change_observer); base::MessageLoop::current()->Run(); EXPECT_EQ(1, dns_change_observer.initial_notifications_count()); EXPECT_EQ(0, dns_change_observer.change_notifications_count()); NetworkChangeNotifier::RemoveDNSObserver(&dns_change_observer); } TEST_F(NetworkChangeNotifierAndroidTest, NetworkCallbacks) { ForceNetworkHandlesSupportedForTesting(); TestNetworkObserver network_observer; NetworkChangeNotifier::AddNetworkObserver(&network_observer); // Test empty values EXPECT_EQ(NetworkChangeNotifier::kInvalidNetworkHandle, NetworkChangeNotifier::GetDefaultNetwork()); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, NetworkChangeNotifier::GetNetworkConnectionType(100)); NetworkChangeNotifier::NetworkList network_list; NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(0u, network_list.size()); // Test connecting network FakeNetworkChange(CONNECTED, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(CONNECTED, 100); EXPECT_EQ(NetworkChangeNotifier::kInvalidNetworkHandle, NetworkChangeNotifier::GetDefaultNetwork()); // Test GetConnectedNetworks() NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(1u, network_list.size()); EXPECT_EQ(100, network_list[0]); // Test GetNetworkConnectionType() EXPECT_EQ(NetworkChangeNotifier::CONNECTION_WIFI, NetworkChangeNotifier::GetNetworkConnectionType(100)); // Test deduplication of connecting signal FakeNetworkChange(CONNECTED, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); // Test connecting another network FakeNetworkChange(CONNECTED, 101, NetworkChangeNotifier::CONNECTION_3G); network_observer.ExpectChange(CONNECTED, 101); NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(2u, network_list.size()); EXPECT_EQ(100, network_list[0]); EXPECT_EQ(101, network_list[1]); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_WIFI, NetworkChangeNotifier::GetNetworkConnectionType(100)); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_3G, NetworkChangeNotifier::GetNetworkConnectionType(101)); // Test lingering network FakeNetworkChange(SOON_TO_DISCONNECT, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(SOON_TO_DISCONNECT, 100); NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(2u, network_list.size()); EXPECT_EQ(100, network_list[0]); EXPECT_EQ(101, network_list[1]); // Test disconnecting network FakeNetworkChange(DISCONNECTED, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(DISCONNECTED, 100); NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(1u, network_list.size()); EXPECT_EQ(101, network_list[0]); // Test deduplication of disconnecting signal FakeNetworkChange(DISCONNECTED, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); // Test delay of default network signal until connect signal FakeNetworkChange(MADE_DEFAULT, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); FakeNetworkChange(CONNECTED, 100, NetworkChangeNotifier::CONNECTION_WIFI); network_observer.ExpectChange(MADE_DEFAULT, 100); EXPECT_EQ(100, NetworkChangeNotifier::GetDefaultNetwork()); // Test change of default FakeNetworkChange(MADE_DEFAULT, 101, NetworkChangeNotifier::CONNECTION_3G); network_observer.ExpectChange(MADE_DEFAULT, 101); EXPECT_EQ(101, NetworkChangeNotifier::GetDefaultNetwork()); // Test deduplication default signal FakeNetworkChange(MADE_DEFAULT, 101, NetworkChangeNotifier::CONNECTION_3G); network_observer.ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); // Test that networks can change type FakeNetworkChange(CONNECTED, 101, NetworkChangeNotifier::CONNECTION_4G); network_observer.ExpectChange(NONE, NetworkChangeNotifier::kInvalidNetworkHandle); EXPECT_EQ(NetworkChangeNotifier::CONNECTION_4G, NetworkChangeNotifier::GetNetworkConnectionType(101)); // Test purging the network list NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(2u, network_list.size()); EXPECT_EQ(100, network_list[0]); EXPECT_EQ(101, network_list[1]); network_list.erase(network_list.begin() + 1); // Remove network 101 FakeUpdateActiveNetworkList(network_list); network_observer.ExpectChange(DISCONNECTED, 101); NetworkChangeNotifier::GetConnectedNetworks(&network_list); EXPECT_EQ(1u, network_list.size()); EXPECT_EQ(100, network_list[0]); EXPECT_EQ(NetworkChangeNotifier::kInvalidNetworkHandle, NetworkChangeNotifier::GetDefaultNetwork()); NetworkChangeNotifier::RemoveNetworkObserver(&network_observer); } } // namespace net