// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/ash/components/dbus/shill/shill_service_client.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/test/browser_test.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/network_change_notifier.h"
#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace ash {
namespace {
class NetObserver : public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
NetObserver() {
net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
last_connection_type_ = net::NetworkChangeNotifier::GetConnectionType();
}
~NetObserver() override {
net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
void WaitForConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
while (last_connection_type_ != type) {
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
run_loop_.reset();
}
}
// net::NetworkChangeNotifier:NetworkChangeObserver:
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override {
change_count_++;
last_connection_type_ = type;
// TODO(b/229673213): Remove log once flakiness is fixed.
LOG(INFO) << "NetworkChangeObserver was called, change count increased to "
<< change_count_
<< " Last connection type is now: " << last_connection_type_;
if (run_loop_)
run_loop_->Quit();
}
int change_count_ = 0;
net::NetworkChangeNotifier::ConnectionType last_connection_type_;
private:
std::unique_ptr<base::RunLoop> run_loop_;
};
class NetworkServiceObserver
: public network::NetworkConnectionTracker::NetworkConnectionObserver {
public:
NetworkServiceObserver() {
content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
// TODO(b/229673213): Remove log once flakiness is fixed.
LOG(INFO) << "NetworkServiceObserver get connection type";
content::GetNetworkConnectionTracker()->GetConnectionType(
&last_connection_type_,
base::BindOnce(&NetworkServiceObserver::OnConnectionChanged,
weak_factory_.GetWeakPtr()));
}
~NetworkServiceObserver() override {
content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(
this);
}
void WaitForConnectionType(network::mojom::ConnectionType type) {
while (last_connection_type_ != type) {
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
run_loop_.reset();
}
}
// network::NetworkConnectionTracker::NetworkConnectionObserver:
void OnConnectionChanged(network::mojom::ConnectionType type) override {
change_count_++;
last_connection_type_ = type;
// TODO(b/229673213): Remove log once flakiness is fixed.
LOG(INFO) << "NetworkServiceObserver was called, change count increased to "
<< change_count_
<< " Last connection type is now: " << last_connection_type_;
if (run_loop_)
run_loop_->Quit();
}
int change_count_ = 0;
network::mojom::ConnectionType last_connection_type_;
private:
std::unique_ptr<base::RunLoop> run_loop_;
base::WeakPtrFactory<NetworkServiceObserver> weak_factory_{this};
};
} // namespace
class NetworkChangeManagerClientBrowserTest : public InProcessBrowserTest {
public:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
// Make sure everyone thinks we have an ethernet connection.
NetObserver().WaitForConnectionType(
net::NetworkChangeNotifier::CONNECTION_ETHERNET);
NetworkServiceObserver().WaitForConnectionType(
network::mojom::ConnectionType::CONNECTION_ETHERNET);
// Wait for all services to be removed.
ShillServiceClient::Get()->GetTestInterface()->ClearServices();
base::RunLoop().RunUntilIdle();
}
ShillServiceClient::TestInterface* service_client() {
return ShillServiceClient::Get()->GetTestInterface();
}
};
// Tests that network changes from shill are received by both the
// NetworkChangeNotifier and NetworkConnectionTracker.
IN_PROC_BROWSER_TEST_F(NetworkChangeManagerClientBrowserTest,
ReceiveNotifications) {
NetObserver net_observer;
NetworkServiceObserver network_service_observer;
service_client()->AddService("wifi", "wifi", "wifi", shill::kTypeWifi,
shill::kStateOnline, true);
net_observer.WaitForConnectionType(
net::NetworkChangeNotifier::CONNECTION_WIFI);
// NetworkChangeNotifier will send a CONNECTION_NONE notification before
// the CONNECTION_WIFI one.
EXPECT_EQ(2, net_observer.change_count_);
EXPECT_EQ(net::NetworkChangeNotifier::CONNECTION_WIFI,
net_observer.last_connection_type_);
network_service_observer.WaitForConnectionType(
network::mojom::ConnectionType::CONNECTION_WIFI);
EXPECT_EQ(2, network_service_observer.change_count_);
EXPECT_EQ(network::mojom::ConnectionType::CONNECTION_WIFI,
network_service_observer.last_connection_type_);
}
// Tests that the NetworkChangeManagerClient reconnects to the network service
// after it gets disconnected.
IN_PROC_BROWSER_TEST_F(NetworkChangeManagerClientBrowserTest,
ReconnectToNetworkService) {
NetworkServiceObserver network_service_observer;
// Manually call SimulateCrash instead of
// BrowserTestBase::SimulateNetworkServiceCrash to avoid the cleanup and
// reconnection work it does for you.
mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
content::GetNetworkService()->BindTestInterfaceForTesting(
network_service_test.BindNewPipeAndPassReceiver());
IgnoreNetworkServiceCrashes();
network_service_test->SimulateCrash();
service_client()->AddService("wifi", "wifi", "wifi", shill::kTypeWifi,
shill::kStateOnline, true);
NetObserver().WaitForConnectionType(
net::NetworkChangeNotifier::CONNECTION_WIFI);
network_service_observer.WaitForConnectionType(
network::mojom::ConnectionType::CONNECTION_WIFI);
EXPECT_EQ(2, network_service_observer.change_count_);
}
} // namespace ash