aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Rossetto <aaron.rossetto@ni.com>2020-05-21 11:06:05 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-05-28 14:49:32 -0500
commit94b09ecadd278878779c47dd55d2503c1ba48d39 (patch)
tree7a7409f26c8b9003dddfef66c145771578809ea8
parentcb99b720eee76dcf83ac89a2107f516443372b7f (diff)
downloaduhd-94b09ecadd278878779c47dd55d2503c1ba48d39.tar.gz
uhd-94b09ecadd278878779c47dd55d2503c1ba48d39.tar.bz2
uhd-94b09ecadd278878779c47dd55d2503c1ba48d39.zip
tests: Add unit test for USE_MAP prop forwarding policy
This commit adds a unit test for the USE_MAP property forwarding policy. It also adds a pair of new mock RFNoC nodes for use in unit testing: - mock_edge_node_t is a node with a configurable number of input and output ports each having an edge property named 'prop' associated with each. The node is also able to source actions from any of its edges and records incoming actions in a map. - mock_routing_node_t is a do-nothing node specifically for testing property and action forwarding between edges with the USE_MAP forwarding strategy. The node has functions to configure the property and action forwarding maps.
-rw-r--r--host/tests/rfnoc_graph_mock_nodes.hpp148
-rw-r--r--host/tests/rfnoc_propprop_test.cpp112
2 files changed, 259 insertions, 1 deletions
diff --git a/host/tests/rfnoc_graph_mock_nodes.hpp b/host/tests/rfnoc_graph_mock_nodes.hpp
index 63e542e40..bfa08bea6 100644
--- a/host/tests/rfnoc_graph_mock_nodes.hpp
+++ b/host/tests/rfnoc_graph_mock_nodes.hpp
@@ -428,4 +428,152 @@ private:
};
size_t mock_terminator_t::counter = 0;
+/*! Mock node with configurable number of input and output ports that have
+ * an edge property associated with each. The node can source actions with
+ * key 'action' from any of its edges. Incoming actions with key 'action'
+ * are stored in a (source port --> list of incoming actions) map.
+ */
+class mock_edge_node_t : public node_t
+{
+public:
+ using received_actions_map_t =
+ std::unordered_map<res_source_info, std::vector<action_info::sptr>>;
+
+ mock_edge_node_t(size_t input_ports,
+ size_t output_ports,
+ const std::string& name = "MOCK_EDGE_NODE")
+ : _input_ports(input_ports), _output_ports(output_ports), _name(name)
+ {
+ _in_props.reserve(_input_ports);
+ _out_props.reserve(_output_ports);
+ set_action_forwarding_policy(forwarding_policy_t::ONE_TO_ONE);
+
+ for (size_t i = 0; i < _input_ports; i++) {
+ _in_props.emplace_back(
+ property_t<int>{"prop", 0, {res_source_info::INPUT_EDGE, i}});
+ register_property(&_in_props.back());
+ }
+ for (size_t i = 0; i < _output_ports; i++) {
+ _out_props.emplace_back(
+ property_t<int>{"prop", 0, {res_source_info::OUTPUT_EDGE, i}});
+ register_property(&_out_props.back());
+ }
+
+ register_action_handler(
+ "action", [this](const res_source_info& src, action_info::sptr action) {
+ auto itr = _received_actions.find(src);
+ if (itr == _received_actions.end()) {
+ _received_actions.insert({src, {action}});
+ } else {
+ itr->second.push_back(action);
+ }
+ });
+ }
+
+ template <typename T>
+ void set_edge_property(
+ const std::string& id, const T& val, const res_source_info& rsi)
+ {
+ node_t::set_property<T>(id, val, rsi);
+ }
+
+ template <typename T>
+ T get_edge_property(const std::string& id, const res_source_info& rsi)
+ {
+ return node_t::get_property<T>(id, rsi);
+ }
+
+ size_t get_num_input_ports() const
+ {
+ return _input_ports;
+ }
+
+ size_t get_num_output_ports() const
+ {
+ return _output_ports;
+ }
+
+ std::string get_unique_id() const
+ {
+ return _name;
+ }
+
+ void post_input_edge_action(action_info::sptr action, size_t port)
+ {
+ UHD_ASSERT_THROW(port < _input_ports);
+ post_action({res_source_info::INPUT_EDGE, port}, action);
+ }
+
+ void post_output_edge_action(action_info::sptr action, size_t port)
+ {
+ UHD_ASSERT_THROW(port < _output_ports);
+ post_action({res_source_info::OUTPUT_EDGE, port}, action);
+ }
+
+ const received_actions_map_t& get_received_actions_map() const
+ {
+ return _received_actions;
+ }
+
+ void clear_received_actions_map()
+ {
+ _received_actions.clear();
+ }
+
+private:
+ size_t _input_ports;
+ size_t _output_ports;
+ std::string _name;
+ std::vector<property_t<int>> _in_props;
+ std::vector<property_t<int>> _out_props;
+ received_actions_map_t _received_actions;
+};
+
+/*! Do-nothing mock node used for testing property and action propagation
+ * between various edges with the USE_MAP forwarding strategy.
+ */
+class mock_routing_node_t : public node_t
+{
+public:
+ mock_routing_node_t(size_t input_ports, size_t output_ports)
+ : _input_ports(input_ports), _output_ports(output_ports)
+ {
+ // By default, the node will drop incoming properties and actions.
+ // Call set_property_prop_map() or set_action_forwarding_map() to
+ // configure the node to use the provided map.
+ set_prop_forwarding_policy(forwarding_policy_t::DROP);
+ set_action_forwarding_policy(forwarding_policy_t::DROP);
+ }
+
+ size_t get_num_input_ports() const
+ {
+ return _input_ports;
+ }
+
+ size_t get_num_output_ports() const
+ {
+ return _output_ports;
+ }
+
+ std::string get_unique_id() const
+ {
+ return "MOCK_ROUTING_NODE";
+ }
+
+ void set_prop_forwarding_map(const node_t::forwarding_map_t& fwd_map)
+ {
+ set_prop_forwarding_policy(forwarding_policy_t::USE_MAP);
+ node_t::set_prop_forwarding_map(fwd_map);
+ }
+
+ void set_action_forwarding_map(const node_t::forwarding_map_t& fwd_map)
+ {
+ set_action_forwarding_policy(forwarding_policy_t::USE_MAP);
+ node_t::set_action_forwarding_map(fwd_map);
+ }
+
+private:
+ size_t _input_ports;
+ size_t _output_ports;
+};
#endif /* INCLUDED_LIBUHD_TESTS_MOCK_NODES_HPP */
diff --git a/host/tests/rfnoc_propprop_test.cpp b/host/tests/rfnoc_propprop_test.cpp
index 2b8cd635c..224783e22 100644
--- a/host/tests/rfnoc_propprop_test.cpp
+++ b/host/tests/rfnoc_propprop_test.cpp
@@ -156,7 +156,6 @@ public:
property_t<double> _x4{"x4", 4.0, {res_source_info::USER}};
};
-
// Do some sanity checks on the mock just so we don't get surprised later
BOOST_AUTO_TEST_CASE(test_mock)
{
@@ -430,3 +429,114 @@ BOOST_AUTO_TEST_CASE(test_circular_deps)
mock_circular_prop_node.set_property<double>("x1", 5.0, 0);
BOOST_CHECK_EQUAL(mock_circular_prop_node.get_property<double>("x4"), 4 * 5.0);
}
+
+BOOST_AUTO_TEST_CASE(test_propagation_map)
+{
+ // Set up the graph
+ node_accessor_t node_accessor{};
+ uhd::rfnoc::detail::graph_t graph{};
+
+ constexpr size_t NUM_INPUTS = 8;
+ constexpr size_t NUM_OUTPUTS = 8;
+
+ node_t::forwarding_map_t fwd_map = {
+ // input edges 0-3 --> output edges 3-0
+ {{res_source_info::INPUT_EDGE, 0}, {{res_source_info::OUTPUT_EDGE, 3}}},
+ {{res_source_info::INPUT_EDGE, 1}, {{res_source_info::OUTPUT_EDGE, 2}}},
+ {{res_source_info::INPUT_EDGE, 2}, {{res_source_info::OUTPUT_EDGE, 1}}},
+ {{res_source_info::INPUT_EDGE, 3}, {{res_source_info::OUTPUT_EDGE, 0}}},
+ // input edge 4 --> output edges 4 and 5
+ {{res_source_info::INPUT_EDGE, 4},
+ {{res_source_info::OUTPUT_EDGE, 4}, {res_source_info::OUTPUT_EDGE, 5}}},
+ // input edge 5 --> output edges 6 and 7
+ {{res_source_info::INPUT_EDGE, 5},
+ {{res_source_info::OUTPUT_EDGE, 6}, {res_source_info::OUTPUT_EDGE, 7}}},
+ // input edge 6 no destination (i.e. drop)
+ {{res_source_info::INPUT_EDGE, 6}, {}}
+ // input edge 7 not in map (i.e. drop)
+ };
+
+ mock_edge_node_t input{0, NUM_INPUTS, "MOCK_EDGE_NODE<input>"};
+ mock_routing_node_t middle{NUM_INPUTS, NUM_OUTPUTS};
+ mock_edge_node_t output{NUM_OUTPUTS, 0, "MOCK_EDGE_NODE<output>"};
+
+ middle.set_prop_forwarding_map(fwd_map);
+
+ // These init calls would normally be done by the framework
+ node_accessor.init_props(&input);
+ node_accessor.init_props(&middle);
+ node_accessor.init_props(&output);
+
+ // Prime the output edge properties on the input block
+ for (size_t i = 0; i < NUM_INPUTS; i++) {
+ input.set_edge_property<int>("prop", 100 + i, {res_source_info::OUTPUT_EDGE, i});
+ }
+
+ using graph_edge_t = uhd::rfnoc::detail::graph_t::graph_edge_t;
+
+ // Connect the nodes in the graph
+ for (size_t i = 0; i < NUM_INPUTS; i++) {
+ graph.connect(&input, &middle, {i, i, graph_edge_t::DYNAMIC, true});
+ }
+ for (size_t i = 0; i < NUM_OUTPUTS; i++) {
+ graph.connect(&middle, &output, {i, i, graph_edge_t::DYNAMIC, true});
+ }
+ UHD_LOG_INFO("TEST", "Now testing map-driven property propagation");
+ graph.commit();
+
+ // Verify that the properties were propagated per the table
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 0}), 103);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 1}), 102);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 2}), 101);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 3}), 100);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 4}), 104);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 5}), 104);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 6}), 105);
+ BOOST_CHECK_EQUAL(
+ output.get_edge_property<int>("prop", {res_source_info::INPUT_EDGE, 7}), 105);
+}
+
+BOOST_AUTO_TEST_CASE(test_propagation_map_exception_invalid_destination)
+{
+ // Set up the graph
+ node_accessor_t node_accessor{};
+ uhd::rfnoc::detail::graph_t graph{};
+
+ // Create a map that will generate an exception at propagation time due
+ // to the mapping pointing to a non-existent port
+ node_t::forwarding_map_t no_port_fwd_map = {
+ // input edge 0 --> output edge 1 (output port does not exist)
+ {{res_source_info::INPUT_EDGE, 0}, {{res_source_info::OUTPUT_EDGE, 1}}}};
+
+ mock_edge_node_t generator{0, 1, "MOCK_EDGE_NODE<generator>"};
+ mock_routing_node_t router{1, 1};
+ mock_edge_node_t receiver{1, 0, "MOCK_EDGE_NODE<receiver>"};
+
+ router.set_prop_forwarding_map(no_port_fwd_map);
+
+ // These init calls would normally be done by the framework
+ node_accessor.init_props(&generator);
+ node_accessor.init_props(&router);
+ node_accessor.init_props(&receiver);
+
+ generator.set_edge_property<int>("prop", 100, {res_source_info::OUTPUT_EDGE, 0});
+
+ using graph_edge_t = uhd::rfnoc::detail::graph_t::graph_edge_t;
+
+ // Connect the nodes in the graph
+ graph.connect(&generator, &router, {0, 0, graph_edge_t::DYNAMIC, true});
+ graph.connect(&router, &receiver, {0, 0, graph_edge_t::DYNAMIC, true});
+
+ UHD_LOG_INFO("TEST",
+ "Now testing map-driven property propagation with invalid map (no destination "
+ "port)");
+ BOOST_REQUIRE_THROW(graph.commit(), uhd::rfnoc_error);
+}
+