chromium/chrome/browser/ash/network_change_manager/network_change_manager_client_browsertest.cc

// 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