blob: 1ec8c1b23028c3acefbca87ced523707f3b2beda [file]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime_probe/functions/network.h"
#include <map>
#include <optional>
#include <set>
#include <string>
#include <base/containers/span.h>
#include <base/files/file_path.h>
#include <base/strings/stringprintf.h>
#include <brillo/variant_dictionary.h>
#include <dbus/shill/dbus-constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "runtime_probe/utils/function_test_utils.h"
#include "shill/dbus-constants.h"
namespace runtime_probe {
namespace {
using ::testing::_;
using ::testing::Eq;
using ::testing::Pointee;
using ::testing::Return;
class MockNetworkFunction : public NetworkFunction {
using NetworkFunction::NetworkFunction;
public:
NAME_PROBE_FUNCTION("mock_network");
MOCK_METHOD(std::optional<std::string>,
GetNetworkType,
(),
(const, override));
};
class NetworkFunctionTest : public BaseFunctionTest {
protected:
void SetNetworkDevice(const std::string& dev_name,
const std::string& network_type,
const std::string& interface_name = "") {
const std::string bus_dev =
"/sys/devices/pci0000:00/0000:00:08.1" + dev_name;
const std::string bus_dev_relative_to_sys = "../../../";
SetSymbolicLink(bus_dev, {"/sys/class/net", dev_name, "device"});
// The symbolic link is for getting the bus type.
SetSymbolicLink({bus_dev_relative_to_sys, "bus", "pci"},
{bus_dev, "subsystem"});
SetFile({bus_dev, "device"}, "0x1111");
SetFile({bus_dev, "vendor"}, "0x2222");
SetFile({bus_dev, "class"}, "0x010203");
std::string interface = interface_name;
if (interface.empty()) {
interface = dev_name;
}
shill_devices_["/dev/" + dev_name] = {
{shill::kInterfaceProperty, interface},
{shill::kTypeProperty, network_type}};
mock_context()->SetShillProxies(shill_devices_);
}
void SetUsbNetworkDevice(const std::string& dev_name,
const std::string& network_type,
const std::string& removable) {
const std::string bus_dev =
"/sys/devices/pci0000:00/0000:00:08.1/0000:03:00.3/usb2/2-3" + dev_name;
const std::string bus_dev_relative_to_sys = "../../../../../../";
const std::string interface_name = "2-3:1.0";
SetSymbolicLink({bus_dev, interface_name},
{"/sys/class/net", dev_name, "device"});
// The symbolic link is for getting the bus type.
SetSymbolicLink({bus_dev_relative_to_sys, "bus", "usb"},
{bus_dev, interface_name, "subsystem"});
SetFile({bus_dev, "idProduct"}, "0x1111");
SetFile({bus_dev, "idVendor"}, "0x2222");
SetFile({bus_dev, "removable"}, removable);
shill_devices_["/dev/" + dev_name] = {{shill::kInterfaceProperty, dev_name},
{shill::kTypeProperty, network_type}};
mock_context()->SetShillProxies(shill_devices_);
}
std::map<std::string, brillo::VariantDictionary> shill_devices_;
};
TEST_F(NetworkFunctionTest, ProbeNetwork) {
SetNetworkDevice("wlan0", shill::kTypeWifi);
auto probe_function = CreateProbeFunction<NetworkFunction>();
auto result = EvalProbeFunction(probe_function.get());
EXPECT_EQ(result.size(), 1);
EXPECT_TRUE(result[0].GetDict().FindString("path"));
EXPECT_TRUE(result[0].GetDict().FindString("bus_type"));
}
TEST_F(NetworkFunctionTest, ProbeNetworkByType) {
SetNetworkDevice("wlan0", shill::kTypeWifi);
SetNetworkDevice("eth0", shill::kTypeEthernet);
SetNetworkDevice("wwan0", shill::kTypeCellular);
const std::set<std::string> expected_types{
shill::kTypeWifi, shill::kTypeEthernet, shill::kTypeCellular};
// Probe all.
{
auto probe_function = CreateProbeFunction<NetworkFunction>();
auto result = EvalProbeFunction(probe_function.get());
std::set<std::string> result_types;
for (const auto& each_result : result) {
auto* type = each_result.GetDict().FindString("type");
if (type) {
result_types.insert(*type);
}
}
EXPECT_EQ(result_types, expected_types);
}
// Filter by each type.
for (const auto& expected_type : expected_types) {
base::DictValue arg;
arg.Set("device_type", expected_type);
auto probe_function = CreateProbeFunction<NetworkFunction>(arg);
auto result = EvalProbeFunction(probe_function.get());
EXPECT_EQ(result.size(), 1);
EXPECT_THAT(result[0].GetDict().FindString("type"),
Pointee(Eq(expected_type)));
}
// TODO(b/269822306): The below two do the same thing as the above, but use
// the old interface to pass the type. Remove this after we done the
// migration.
// Probe all.
{
auto probe_function = CreateProbeFunction<MockNetworkFunction>();
EXPECT_CALL(*probe_function, GetNetworkType())
.WillOnce(Return(std::nullopt));
auto result = EvalProbeFunction(probe_function.get());
std::set<std::string> result_types;
for (const auto& each_result : result) {
auto* type = each_result.GetDict().FindString("type");
if (type) {
result_types.insert(*type);
}
}
EXPECT_EQ(result_types, expected_types);
}
// Filter by each type.
for (const auto& expected_type : expected_types) {
auto probe_function = CreateProbeFunction<MockNetworkFunction>();
EXPECT_CALL(*probe_function, GetNetworkType())
.WillOnce(Return(expected_type));
auto result = EvalProbeFunction(probe_function.get());
EXPECT_EQ(result.size(), 1);
EXPECT_THAT(result[0].GetDict().FindString("type"),
Pointee(Eq(expected_type)));
}
}
TEST_F(NetworkFunctionTest, CreateNetworkFunctionFailed) {
base::DictValue arg;
arg.Set("device_type", "unknown_type");
auto probe_function = CreateProbeFunction<NetworkFunction>(arg);
EXPECT_FALSE(probe_function);
}
TEST_F(NetworkFunctionTest, ProbeAllFilterExternalEthernet) {
SetUsbNetworkDevice("wwan0", shill::kTypeCellular, "unknown");
SetUsbNetworkDevice("wlan0", shill::kTypeWifi, "unknown");
SetUsbNetworkDevice("eth0", shill::kTypeEthernet, "unknown");
auto probe_function = CreateProbeFunction<NetworkFunction>();
auto result = EvalProbeFunction(probe_function.get());
EXPECT_EQ(result.size(), 2);
}
TEST_F(NetworkFunctionTest, ProbeAll_ShillReportsDefaultCellularInterface) {
SetNetworkDevice("wwan0", shill::kTypeCellular,
shill::kCellularDefaultInterfaceName);
SetNetworkDevice("eth0", shill::kTypeEthernet);
auto probe_function = CreateProbeFunction<NetworkFunction>();
auto result = EvalProbeFunction(probe_function.get());
auto ans = CreateProbeResultFromJson(base::StringPrintf(
R"JSON(
[
{
"bus_type": "pci",
"path": "%s",
"pci_class": "0x010203",
"pci_device_id": "0x1111",
"pci_vendor_id": "0x2222",
"type": "cellular"
}, {
"bus_type": "pci",
"path": "%s",
"pci_class": "0x010203",
"pci_device_id": "0x1111",
"pci_vendor_id": "0x2222",
"type": "ethernet"
}
]
)JSON",
GetPathUnderRoot("/sys/class/net/wwan0").value().c_str(),
GetPathUnderRoot("/sys/class/net/eth0").value().c_str()));
ExpectUnorderedListEqual(result, ans);
}
} // namespace
} // namespace runtime_probe