Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Development/cmake/NmosCppTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ set(NMOS_CPP_TEST_NMOS_TEST_SOURCES
nmos/test/jwt_generator_test.cpp
nmos/test/jwt_validation_test.cpp
nmos/test/mdns_test.cpp
nmos/test/node_interfaces_test.cpp
nmos/test/paging_utils_test.cpp
nmos/test/query_api_test.cpp
nmos/test/sdp_test_utils.cpp
Expand Down
50 changes: 42 additions & 8 deletions Development/nmos/node_interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ namespace nmos
return !chassis_id.empty() ? value::string(chassis_id) : value::null();
}

utility::string_t parse_node_interfaces_chassis_id(const web::json::value& chassis_id)
{
return chassis_id.is_null() ? utility::string_t{} : chassis_id.as_string();
}

// Port ID must be a MAC address
web::json::value make_node_interfaces_port_id(const utility::string_t& port_id)
{
Expand All @@ -25,38 +30,67 @@ namespace nmos
}
}

// make node interface JSON data
web::json::value make_node_interface(const node_interface& interface)
{
using web::json::value_of;

const bool keep_order = true;

const auto has_attached = !interface.attached_chassis_id.empty() && !interface.attached_port_id.empty();

return value_of({
{ nmos::fields::chassis_id, details::make_node_interfaces_chassis_id(interface.chassis_id) },
{ nmos::fields::port_id, details::make_node_interfaces_port_id(interface.port_id) },
{ nmos::fields::name, interface.name },
{ has_attached ? nmos::fields::attached_network_device.key : U(""), value_of({
{ nmos::fields::chassis_id, interface.attached_chassis_id },
{ nmos::fields::port_id, interface.attached_port_id }
}, keep_order) }
}, keep_order);
}

// parse node interface JSON data
node_interface parse_node_interface(const web::json::value& interface)
{
const auto& attached = nmos::fields::attached_network_device(interface);
return {
details::parse_node_interfaces_chassis_id(interface.at(nmos::fields::chassis_id)),
nmos::fields::port_id(interface),
nmos::fields::name(interface),
attached.is_object() ? nmos::fields::chassis_id(attached) : utility::string_t{},
attached.is_object() ? nmos::fields::port_id(attached) : utility::string_t{}
};
}

// make node interfaces JSON data, for the specified map from local interface_id
// no attached_network_device details are included
web::json::value make_node_interfaces(const std::map<utility::string_t, node_interface>& interfaces)
{
using web::json::value_from_elements;
using web::json::value_of;

return value_from_elements(interfaces | boost::adaptors::transformed([](const std::map<utility::string_t, node_interface>::value_type& interface)
{
return value_of({
{ nmos::fields::chassis_id, details::make_node_interfaces_chassis_id(interface.second.chassis_id) },
{ nmos::fields::port_id, details::make_node_interfaces_port_id(interface.second.port_id) },
{ nmos::fields::name, interface.second.name }
});
return make_node_interface(interface.second);
}));
}

namespace experimental
{
// make a map from local interface_id to the (recommended) node interface details for the specified host interfaces
// no attached_network_device details are included
std::map<utility::string_t, node_interface> node_interfaces(const std::vector<web::hosts::experimental::host_interface>& host_interfaces)
{
return boost::copy_range<std::map<utility::string_t, node_interface>>(host_interfaces | boost::adaptors::transformed([&](const web::hosts::experimental::host_interface& interface)
{
return std::map<utility::string_t, node_interface>::value_type{
interface.name,
{ host_interfaces.front().physical_address, interface.physical_address, interface.name }
{ host_interfaces.front().physical_address, interface.physical_address, interface.name, {}, {} }
};
}));
}

// make a map from local interface_id to the (recommended) node interface details
// no attached_network_device details are included
std::map<utility::string_t, node_interface> node_interfaces()
{
return node_interfaces(web::hosts::experimental::host_interfaces());
Expand Down
18 changes: 17 additions & 1 deletion Development/nmos/node_interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define NMOS_NODE_INTERFACES_H

#include <map>
#include <tuple>
#include <vector>
#include "cpprest/details/basic_types.h"

Expand Down Expand Up @@ -33,18 +34,33 @@ namespace nmos
utility::string_t port_id;
// Interface name (recommended to be the local interface_id)
utility::string_t name;
// Attached network device chassis ID; empty string indicates attached_network_device is omitted
utility::string_t attached_chassis_id;
// Attached network device port ID; empty string indicates attached_network_device is omitted
utility::string_t attached_port_id;

auto tied() const -> decltype(std::tie(chassis_id, port_id, name, attached_chassis_id, attached_port_id)) { return std::tie(chassis_id, port_id, name, attached_chassis_id, attached_port_id); }
friend bool operator==(const node_interface& lhs, const node_interface& rhs) { return lhs.tied() == rhs.tied(); }
friend bool operator!=(const node_interface& lhs, const node_interface& rhs) { return !(lhs == rhs); }
};

// make node interface JSON data
web::json::value make_node_interface(const node_interface& interface);

// parse node interface JSON data
node_interface parse_node_interface(const web::json::value& interface);

// make node interfaces JSON data, for the specified map from local interface_id
// no attached_network_device details are included
web::json::value make_node_interfaces(const std::map<utility::string_t, node_interface>& interfaces);

namespace experimental
{
// make a map from local interface_id to the (recommended) node interface details for the specified host interfaces
// no attached_network_device details are included
std::map<utility::string_t, node_interface> node_interfaces(const std::vector<web::hosts::experimental::host_interface>& host_interfaces);

// make a map from local interface_id to the (recommended) node interface details
// no attached_network_device details are included
std::map<utility::string_t, node_interface> node_interfaces();
}
}
Expand Down
67 changes: 67 additions & 0 deletions Development/nmos/test/node_interfaces_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// The first "test" is of course whether the header compiles standalone
#include "nmos/node_interfaces.h"

#include "bst/test/test.h"
#include "nmos/json_fields.h"

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testMakeParseNodeInterface)
{
using web::json::value_of;

const nmos::node_interface iface{
U("aa-bb-cc-dd-ee-01"),
U("aa-bb-cc-dd-ee-ff"),
U("eth0"),
U(""),
U("")
};

const auto json = nmos::make_node_interface(iface);
BST_REQUIRE(!json.at(nmos::fields::chassis_id).is_null());
BST_REQUIRE_EQUAL(U("aa-bb-cc-dd-ee-01"), nmos::fields::chassis_id(json));
BST_REQUIRE_EQUAL(U("aa-bb-cc-dd-ee-ff"), nmos::fields::port_id(json));
BST_REQUIRE_EQUAL(U("eth0"), nmos::fields::name(json));
BST_REQUIRE(!json.has_field(nmos::fields::attached_network_device));

BST_REQUIRE(iface == nmos::parse_node_interface(json));
}

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testMakeParseNodeInterfaceNullChassisId)
{
const nmos::node_interface iface{
U(""),
U("aa-bb-cc-dd-ee-ff"),
U("eth0"),
U(""),
U("")
};

const auto json = nmos::make_node_interface(iface);
BST_REQUIRE(json.at(nmos::fields::chassis_id).is_null());
BST_REQUIRE(!json.has_field(nmos::fields::attached_network_device));

BST_REQUIRE(iface == nmos::parse_node_interface(json));
}

////////////////////////////////////////////////////////////////////////////////////////////
BST_TEST_CASE(testMakeParseNodeInterfaceAttachedNetworkDevice)
{
const nmos::node_interface iface{
U(""),
U("aa-bb-cc-dd-ee-ff"),
U("eth0"),
U("11-22-33-44-55-66"),
U("77-88-99-aa-bb-cc")
};

const auto json = nmos::make_node_interface(iface);
BST_REQUIRE(json.has_field(nmos::fields::attached_network_device));

const auto& attached = nmos::fields::attached_network_device(json);
BST_REQUIRE_EQUAL(U("11-22-33-44-55-66"), nmos::fields::chassis_id(attached));
BST_REQUIRE_EQUAL(U("77-88-99-aa-bb-cc"), nmos::fields::port_id(attached));

BST_REQUIRE(iface == nmos::parse_node_interface(json));
}
Loading