123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- // 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.
- #include "net/base/network_change_notifier_win.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/run_loop.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/win/windows_version.h"
- #include "net/base/network_change_notifier.h"
- #include "net/base/network_change_notifier_factory.h"
- #include "net/test/test_with_task_environment.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using ::testing::AtLeast;
- using ::testing::Invoke;
- using ::testing::Return;
- using ::testing::StrictMock;
- namespace net {
- // Subclass of NetworkChangeNotifierWin that overrides functions so that no
- // Windows API networking function results effect tests.
- class TestNetworkChangeNotifierWin : public NetworkChangeNotifierWin {
- public:
- TestNetworkChangeNotifierWin() {
- last_computed_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
- last_announced_offline_ = false;
- last_computed_connection_cost_ = ConnectionCost::CONNECTION_COST_UNKNOWN;
- sequence_runner_for_registration_ = base::SequencedTaskRunnerHandle::Get();
- }
- TestNetworkChangeNotifierWin(const TestNetworkChangeNotifierWin&) = delete;
- TestNetworkChangeNotifierWin& operator=(const TestNetworkChangeNotifierWin&) =
- delete;
- ~TestNetworkChangeNotifierWin() override {
- // This is needed so we don't try to stop watching for IP address changes,
- // as we never actually started.
- set_is_watching(false);
- }
- // From NetworkChangeNotifierWin.
- void RecomputeCurrentConnectionTypeOnBlockingSequence(
- base::OnceCallback<void(ConnectionType)> reply_callback) const override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(reply_callback),
- NetworkChangeNotifier::CONNECTION_UNKNOWN));
- }
- // From NetworkChangeNotifierWin.
- MOCK_METHOD0(WatchForAddressChangeInternal, bool());
- };
- class TestIPAddressObserver : public NetworkChangeNotifier::IPAddressObserver {
- public:
- TestIPAddressObserver() {
- NetworkChangeNotifier::AddIPAddressObserver(this);
- }
- TestIPAddressObserver(const TestIPAddressObserver&) = delete;
- TestIPAddressObserver& operator=(const TestIPAddressObserver&) = delete;
- ~TestIPAddressObserver() {
- NetworkChangeNotifier::RemoveIPAddressObserver(this);
- }
- MOCK_METHOD0(OnIPAddressChanged, void());
- };
- bool ExitMessageLoopAndReturnFalse() {
- base::RunLoop::QuitCurrentWhenIdleDeprecated();
- return false;
- }
- class NetworkChangeNotifierWinTest : public TestWithTaskEnvironment {
- public:
- // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
- // success. Expects that |network_change_notifier_| has just been created, so
- // it's not watching anything yet, and there have been no previous
- // WatchForAddressChangeInternal failures.
- void StartWatchingAndSucceed() {
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- .Times(1)
- .WillOnce(Return(true));
- network_change_notifier_.WatchForAddressChange();
- EXPECT_TRUE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- // If a task to notify observers of the IP address change event was
- // incorrectly posted, make sure it gets run to trigger a failure.
- base::RunLoop().RunUntilIdle();
- }
- // Calls WatchForAddressChange, and simulates a WatchForAddressChangeInternal
- // failure.
- void StartWatchingAndFail() {
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- // Due to an expected race, it's theoretically possible for more than
- // one call to occur, though unlikely.
- .Times(AtLeast(1))
- .WillRepeatedly(Return(false));
- network_change_notifier_.WatchForAddressChange();
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_LT(0, network_change_notifier_.sequential_failures());
- // If a task to notify observers of the IP address change event was
- // incorrectly posted, make sure it gets run.
- base::RunLoop().RunUntilIdle();
- }
- // Simulates a network change event, resulting in a call to OnObjectSignaled.
- // The resulting call to WatchForAddressChangeInternal then succeeds.
- void SignalAndSucceed() {
- EXPECT_TRUE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- .Times(1)
- .WillOnce(Return(true));
- network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
- EXPECT_TRUE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- // Run the task to notify observers of the IP address change event.
- base::RunLoop().RunUntilIdle();
- }
- // Simulates a network change event, resulting in a call to OnObjectSignaled.
- // The resulting call to WatchForAddressChangeInternal then fails.
- void SignalAndFail() {
- EXPECT_TRUE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(1);
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- // Due to an expected race, it's theoretically possible for more than
- // one call to occur, though unlikely.
- .Times(AtLeast(1))
- .WillRepeatedly(Return(false));
- network_change_notifier_.OnObjectSignaled(INVALID_HANDLE_VALUE);
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_LT(0, network_change_notifier_.sequential_failures());
- // Run the task to notify observers of the IP address change event.
- base::RunLoop().RunUntilIdle();
- }
- // Runs the message loop until WatchForAddressChange is called again, as a
- // result of the already posted task after a WatchForAddressChangeInternal
- // failure. Simulates a success on the resulting call to
- // WatchForAddressChangeInternal.
- void RetryAndSucceed() {
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_LT(0, network_change_notifier_.sequential_failures());
- base::RunLoop run_loop;
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged())
- .Times(1)
- .WillOnce(Invoke(&run_loop, &base::RunLoop::QuitWhenIdle));
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- .Times(1).WillOnce(Return(true));
- run_loop.Run();
- EXPECT_TRUE(network_change_notifier_.is_watching());
- EXPECT_EQ(0, network_change_notifier_.sequential_failures());
- }
- // Runs the message loop until WatchForAddressChange is called again, as a
- // result of the already posted task after a WatchForAddressChangeInternal
- // failure. Simulates a failure on the resulting call to
- // WatchForAddressChangeInternal.
- void RetryAndFail() {
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_LT(0, network_change_notifier_.sequential_failures());
- int initial_sequential_failures =
- network_change_notifier_.sequential_failures();
- EXPECT_CALL(test_ip_address_observer_, OnIPAddressChanged()).Times(0);
- EXPECT_CALL(network_change_notifier_, WatchForAddressChangeInternal())
- // Due to an expected race, it's theoretically possible for more than
- // one call to occur, though unlikely.
- .Times(AtLeast(1))
- .WillRepeatedly(Invoke(ExitMessageLoopAndReturnFalse));
- base::RunLoop().Run();
- EXPECT_FALSE(network_change_notifier_.is_watching());
- EXPECT_LT(initial_sequential_failures,
- network_change_notifier_.sequential_failures());
- // If a task to notify observers of the IP address change event was
- // incorrectly posted, make sure it gets run.
- base::RunLoop().RunUntilIdle();
- }
- bool HasNetworkCostManager() {
- return network_change_notifier_.network_cost_manager_.Get() != nullptr;
- }
- bool HasNetworkCostManagerEventSink() {
- return network_change_notifier_.network_cost_manager_event_sink_.Get() !=
- nullptr;
- }
- NetworkChangeNotifier::ConnectionCost LastComputedConnectionCost() {
- return network_change_notifier_.last_computed_connection_cost_;
- }
- NetworkChangeNotifier::ConnectionCost GetCurrentConnectionCost() {
- return network_change_notifier_.GetCurrentConnectionCost();
- }
- private:
- // Note that the order of declaration here is important.
- // 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_;
- StrictMock<TestNetworkChangeNotifierWin> network_change_notifier_;
- // Must be created after |network_change_notifier_|, so it can add itself as
- // an IPAddressObserver.
- StrictMock<TestIPAddressObserver> test_ip_address_observer_;
- };
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinBasic) {
- StartWatchingAndSucceed();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStart) {
- StartWatchingAndFail();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartOnce) {
- StartWatchingAndFail();
- RetryAndSucceed();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailStartTwice) {
- StartWatchingAndFail();
- RetryAndFail();
- RetryAndSucceed();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinSignal) {
- StartWatchingAndSucceed();
- SignalAndSucceed();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalOnce) {
- StartWatchingAndSucceed();
- SignalAndFail();
- RetryAndSucceed();
- }
- TEST_F(NetworkChangeNotifierWinTest, NetChangeWinFailSignalTwice) {
- StartWatchingAndSucceed();
- SignalAndFail();
- RetryAndFail();
- RetryAndSucceed();
- }
- class TestConnectionCostObserver
- : public NetworkChangeNotifier::ConnectionCostObserver {
- public:
- TestConnectionCostObserver() {}
- TestConnectionCostObserver(const TestConnectionCostObserver&) = delete;
- TestConnectionCostObserver& operator=(const TestConnectionCostObserver&) =
- delete;
- ~TestConnectionCostObserver() override {
- NetworkChangeNotifier::RemoveConnectionCostObserver(this);
- }
- void OnConnectionCostChanged(NetworkChangeNotifier::ConnectionCost) override {
- }
- void Register() { NetworkChangeNotifier::AddConnectionCostObserver(this); }
- };
- TEST_F(NetworkChangeNotifierWinTest, NetworkCostManagerIntegration) {
- // NetworkCostManager integration only exist on Win10+.
- if (base::win::GetVersion() < base::win::Version::WIN10)
- return;
- // Upon creation, none of the NetworkCostManager integration should be
- // initialized yet.
- ASSERT_FALSE(HasNetworkCostManager());
- ASSERT_FALSE(HasNetworkCostManagerEventSink());
- ASSERT_EQ(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
- LastComputedConnectionCost());
- // Asking for the current connection cost should initialize the
- // NetworkCostManager integration, but not the event sink.
- // Note that the actual ConnectionCost value return is irrelevant beyond the
- // fact that it shouldn't be UNKNOWN anymore if the integration is initialized
- // properly.
- NetworkChangeNotifier::ConnectionCost current_connection_cost =
- GetCurrentConnectionCost();
- EXPECT_NE(NetworkChangeNotifier::ConnectionCost::CONNECTION_COST_UNKNOWN,
- current_connection_cost);
- EXPECT_EQ(current_connection_cost, LastComputedConnectionCost());
- EXPECT_TRUE(HasNetworkCostManager());
- EXPECT_FALSE(HasNetworkCostManagerEventSink());
- // Adding a ConnectionCostObserver should initialize the event sink. If the
- // subsequent registration for updates fails, the event sink will get
- // destroyed.
- TestConnectionCostObserver test_connection_cost_observer;
- test_connection_cost_observer.Register();
- // The actual registration happens on a callback, so need to run until idle.
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(HasNetworkCostManagerEventSink());
- }
- } // namespace net
|