blob: dee034fb290ace1d4976e83b159e2c9b19ff4f2c [file] [log] [blame]
// 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/ip_address.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<int(void)>& notifications_count_getter,
const base::Callback<ConnectionType(void)>& 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 FakePurgeActiveNetworkList(NetworkChangeNotifier::NetworkList networks) {
delegate_.FakePurgeActiveNetworkList(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.
std::unique_ptr<NetworkChangeNotifierDelegateAndroid> 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 {
dns_config_.nameservers.push_back(
IPEndPoint(IPAddress(8, 8, 8, 8), 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_;
std::unique_ptr<NetworkChangeNotifierAndroid> 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<double>::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
FakePurgeActiveNetworkList(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