| // Copyright 2018 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 "content/public/test/network_connection_change_simulator.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/run_loop.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "content/public/browser/system_connector.h" |
| #include "content/public/common/network_service_util.h" |
| #include "content/public/common/service_names.mojom.h" |
| #include "net/base/network_change_notifier.h" |
| #include "services/network/public/mojom/network_service_test.mojom.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "net/base/network_change_notifier_posix.h" |
| #include "services/network/public/mojom/network_service.mojom.h" |
| #endif |
| |
| namespace content { |
| |
| // SetConnectionType will block until the network connection changes, and |
| // unblocking it involves posting a task (see |
| // NetworkConnectionTracker::OnNetworkChanged). If SetConnectionType is ever |
| // called downstream of a task run within another RunLoop::Run call, this |
| // class's RunLoop::Run will deadlock because the task needed to unblock it |
| // won't be run. To stop this, this class uses RunLoops that allow nested tasks. |
| constexpr base::RunLoop::Type kRunLoopType = |
| base::RunLoop::Type::kNestableTasksAllowed; |
| |
| NetworkConnectionChangeSimulator::NetworkConnectionChangeSimulator() = default; |
| NetworkConnectionChangeSimulator::~NetworkConnectionChangeSimulator() = default; |
| |
| #if defined(OS_CHROMEOS) |
| void NetworkConnectionChangeSimulator::InitializeChromeosConnectionType() { |
| // Manually set the connection type since ChromeOS's NetworkChangeNotifier |
| // implementation relies on some other class controlling it (normally |
| // NetworkChangeManagerClient), which isn't used on content/. |
| net::NetworkChangeNotifierPosix* network_change_notifier = |
| static_cast<net::NetworkChangeNotifierPosix*>( |
| content::GetNetworkChangeNotifier()); |
| network_change_notifier->OnConnectionChanged( |
| net::NetworkChangeNotifier::CONNECTION_ETHERNET); |
| // If the network service is enabled, set the connection type for its |
| // NetworkChangeNotifier instance as well. |
| if (IsOutOfProcessNetworkService()) { |
| network::mojom::NetworkChangeManagerPtr manager_ptr; |
| network::mojom::NetworkChangeManagerRequest request( |
| mojo::MakeRequest(&manager_ptr)); |
| GetNetworkService()->GetNetworkChangeManager(std::move(request)); |
| manager_ptr->OnNetworkChanged( |
| /*dns_changed=*/false, /*ip_address_changed=*/false, |
| /*connection_type_changed=*/true, |
| network::mojom::ConnectionType::CONNECTION_ETHERNET, |
| /*connection_subtype_changed=*/false, |
| network::mojom::ConnectionSubtype::SUBTYPE_UNKNOWN); |
| } |
| } |
| #endif |
| |
| void NetworkConnectionChangeSimulator::SetConnectionType( |
| network::mojom::ConnectionType type) { |
| network::NetworkConnectionTracker* network_connection_tracker = |
| content::GetNetworkConnectionTracker(); |
| network::mojom::ConnectionType connection_type = |
| network::mojom::ConnectionType::CONNECTION_UNKNOWN; |
| run_loop_ = std::make_unique<base::RunLoop>(kRunLoopType); |
| network_connection_tracker->AddNetworkConnectionObserver(this); |
| SimulateNetworkChange(type); |
| // Make sure the underlying network connection type becomes |type|. |
| // The while loop is necessary because in some machine such as "Builder |
| // linux64 trunk", the |connection_type| can be CONNECTION_ETHERNET before |
| // it changes to |type|. So here it needs to wait until the |
| // |connection_type| becomes |type|. |
| while ( |
| !network_connection_tracker->GetConnectionType( |
| &connection_type, |
| base::BindOnce(&NetworkConnectionChangeSimulator::OnConnectionChanged, |
| base::Unretained(this))) || |
| connection_type != type) { |
| SimulateNetworkChange(type); |
| run_loop_->Run(); |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| } |
| network_connection_tracker->RemoveNetworkConnectionObserver(this); |
| } |
| |
| // static |
| void NetworkConnectionChangeSimulator::SimulateNetworkChange( |
| network::mojom::ConnectionType type) { |
| if (IsOutOfProcessNetworkService()) { |
| network::mojom::NetworkServiceTestPtr network_service_test; |
| GetSystemConnector()->BindInterface(mojom::kNetworkServiceName, |
| &network_service_test); |
| base::RunLoop run_loop(kRunLoopType); |
| network_service_test->SimulateNetworkChange(type, run_loop.QuitClosure()); |
| run_loop.Run(); |
| return; |
| } |
| net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( |
| net::NetworkChangeNotifier::ConnectionType(type)); |
| } |
| |
| void NetworkConnectionChangeSimulator::OnConnectionChanged( |
| network::mojom::ConnectionType connection_type) { |
| DCHECK(run_loop_); |
| run_loop_->Quit(); |
| } |
| |
| } // namespace content |