chromium/net/base/fuchsia/network_interface_cache_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/fuchsia/network_interface_cache.h"

#include <fuchsia/net/interfaces/cpp/fidl.h>
#include <fuchsia/net/interfaces/cpp/fidl_test_base.h>

#include "net/base/network_change_notifier.h"
#include "net/base/network_interfaces.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net::internal {
namespace {

enum : InterfaceProperties::InterfaceId {
  kDefaultInterfaceId = 1,
  kSecondaryInterfaceId = 2
};

using IPv4Octets = std::array<uint8_t, 4>;

constexpr IPv4Octets kDefaultIPv4Address = {192, 168, 0, 2};
constexpr uint8_t kDefaultIPv4Prefix = 16;

constexpr const char kDefaultInterfaceName[] = "net1";

fuchsia::net::IpAddress IpAddressFrom(IPv4Octets octets) {
  fuchsia::net::IpAddress output;
  output.ipv4().addr = octets;
  return output;
}

template <typename T>
fuchsia::net::Subnet SubnetFrom(T octets, uint8_t prefix) {
  fuchsia::net::Subnet output;
  output.addr = IpAddressFrom(octets);
  output.prefix_len = prefix;
  return output;
}

template <typename T>
fuchsia::net::interfaces::Address InterfaceAddressFrom(T octets,
                                                       uint8_t prefix) {
  fuchsia::net::interfaces::Address addr;
  addr.set_addr(SubnetFrom(octets, prefix));
  return addr;
}

template <typename T>
std::vector<T> MakeSingleItemVec(T item) {
  std::vector<T> vec;
  vec.push_back(std::move(item));
  return vec;
}

fuchsia::net::interfaces::Properties DefaultInterfaceProperties(
    fuchsia::hardware::network::DeviceClass device_class =
        fuchsia::hardware::network::DeviceClass::ETHERNET) {
  // For most tests a live interface with an IPv4 address and ethernet class is
  // sufficient.
  fuchsia::net::interfaces::Properties properties;
  properties.set_id(kDefaultInterfaceId);
  properties.set_name(kDefaultInterfaceName);
  properties.set_online(true);
  properties.set_has_default_ipv4_route(true);
  properties.set_has_default_ipv6_route(false);
  properties.set_device_class(fuchsia::net::interfaces::DeviceClass::WithDevice(
      std::move(device_class)));
  properties.set_addresses(MakeSingleItemVec(
      InterfaceAddressFrom(kDefaultIPv4Address, kDefaultIPv4Prefix)));
  return properties;
}

}  // namespace

class NetworkInterfaceCacheTest : public testing::Test {};

TEST_F(NetworkInterfaceCacheTest, AddInterface) {
  NetworkInterfaceCache cache(false);

  auto change_bits = cache.AddInterface(DefaultInterfaceProperties());

  ASSERT_TRUE(change_bits.has_value());
  EXPECT_EQ(change_bits.value(),
            NetworkInterfaceCache::kIpAddressChanged |
                NetworkInterfaceCache::kConnectionTypeChanged);

  NetworkInterfaceList networks;
  EXPECT_TRUE(cache.GetOnlineInterfaces(&networks));
  EXPECT_EQ(networks.size(), 1u);

  EXPECT_EQ(cache.GetConnectionType(),
            NetworkChangeNotifier::CONNECTION_ETHERNET);
}

TEST_F(NetworkInterfaceCacheTest, RemoveInterface) {
  NetworkInterfaceCache cache(false);
  cache.AddInterface(DefaultInterfaceProperties());

  auto change_bits = cache.RemoveInterface(kDefaultInterfaceId);

  ASSERT_TRUE(change_bits.has_value());
  EXPECT_EQ(change_bits.value(),
            NetworkInterfaceCache::kIpAddressChanged |
                NetworkInterfaceCache::kConnectionTypeChanged);

  NetworkInterfaceList networks;
  EXPECT_TRUE(cache.GetOnlineInterfaces(&networks));
  EXPECT_EQ(networks.size(), 0u);

  EXPECT_EQ(cache.GetConnectionType(), NetworkChangeNotifier::CONNECTION_NONE);
}

TEST_F(NetworkInterfaceCacheTest, ChangeInterface) {
  NetworkInterfaceCache cache(false);
  cache.AddInterface(DefaultInterfaceProperties());

  fuchsia::net::interfaces::Properties properties;
  properties.set_id(kDefaultInterfaceId);
  properties.set_device_class(
      fuchsia::net::interfaces::DeviceClass::WithLoopback(
          fuchsia::net::interfaces::Empty()));
  properties.set_addresses({});

  auto change_bits = cache.ChangeInterface(std::move(properties));

  ASSERT_TRUE(change_bits.has_value());
  EXPECT_EQ(change_bits.value(),
            NetworkInterfaceCache::kIpAddressChanged |
                NetworkInterfaceCache::kConnectionTypeChanged);

  NetworkInterfaceList networks;
  EXPECT_TRUE(cache.GetOnlineInterfaces(&networks));
  EXPECT_EQ(networks.size(), 0u);

  EXPECT_EQ(cache.GetConnectionType(), NetworkChangeNotifier::CONNECTION_NONE);
}

// TODO(crbug.com/40721278): Add more tests that exercise different error
// states.

}  // namespace net::internal