diff options
-rw-r--r-- | host/tests/CMakeLists.txt | 12 | ||||
-rw-r--r-- | host/tests/common/CMakeLists.txt | 15 | ||||
-rw-r--r-- | host/tests/common/mock_ctrl_iface_impl.cpp | 35 | ||||
-rw-r--r-- | host/tests/common/mock_ctrl_iface_impl.hpp | 30 | ||||
-rw-r--r-- | host/tests/common/mock_zero_copy.cpp | 29 | ||||
-rw-r--r-- | host/tests/common/mock_zero_copy.hpp | 88 | ||||
-rw-r--r-- | host/tests/device3_test.cpp | 145 |
7 files changed, 295 insertions, 59 deletions
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 44c042f65..0424b1b53 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -11,6 +11,14 @@ include(UHDUnitTest) ######################################################################## +# build test common +######################################################################## +SET(test_common_SOURCEDIR ${CMAKE_CURRENT_SOURCE_DIR}/common) +ADD_SUBDIRECTORY(common) +LINK_DIRECTORIES(test_common_SOURCEDIR) + + +######################################################################## # unit test suite ######################################################################## SET(test_sources @@ -74,12 +82,12 @@ IF(ENABLE_C_API) ENDIF(ENABLE_C_API) INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/lib/include") - +INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/common") #for each source: build an executable, register it as a test FOREACH(test_source ${test_sources}) GET_FILENAME_COMPONENT(test_name ${test_source} NAME_WE) ADD_EXECUTABLE(${test_name} ${test_source}) - TARGET_LINK_LIBRARIES(${test_name} uhd ${Boost_LIBRARIES}) + TARGET_LINK_LIBRARIES(${test_name} uhd uhd_test ${Boost_LIBRARIES}) UHD_ADD_TEST(${test_name} ${test_name}) UHD_INSTALL(TARGETS ${test_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/tests COMPONENT tests) ENDFOREACH(test_source) diff --git a/host/tests/common/CMakeLists.txt b/host/tests/common/CMakeLists.txt new file mode 100644 index 000000000..91a70dfae --- /dev/null +++ b/host/tests/common/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright 2018 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +######################################################################## +# Build uhd_test static lib +######################################################################## +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/lib/include") +ADD_LIBRARY(uhd_test ${CMAKE_CURRENT_SOURCE_DIR}/mock_ctrl_iface_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mock_zero_copy.cpp + ${CMAKE_SOURCE_DIR}/lib/rfnoc/graph_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/rfnoc/async_msg_handler.cpp +)
\ No newline at end of file diff --git a/host/tests/common/mock_ctrl_iface_impl.cpp b/host/tests/common/mock_ctrl_iface_impl.cpp new file mode 100644 index 000000000..24a938e4f --- /dev/null +++ b/host/tests/common/mock_ctrl_iface_impl.cpp @@ -0,0 +1,35 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "mock_ctrl_iface_impl.hpp" +static const uint64_t TEST_NOC_ID = 0xAAAABBBBCCCCDDDD; + +uint64_t mock_ctrl_iface_impl::send_cmd_pkt( + const size_t addr, + const size_t data, + const bool readback, + const uint64_t timestamp +) { + if (not readback) { + std::cout << str(boost::format("[MOCK] poke to addr: %016X, data == %016X") % addr % data) << std::endl; + } else { + std::cout << str(boost::format("[MOCK] peek64 to addr: %016X") % data) << std::endl; + switch (data) { + case uhd::rfnoc::SR_READBACK_REG_ID: + return TEST_NOC_ID; + case uhd::rfnoc::SR_READBACK_REG_FIFOSIZE: + return 0x0000000000010000; + case uhd::rfnoc::SR_READBACK_REG_USER: + return 0x0123456789ABCDEF; + case uhd::rfnoc::SR_READBACK_COMPAT: + return uhd::rfnoc::NOC_SHELL_COMPAT_MAJOR << 32 | + uhd::rfnoc::NOC_SHELL_COMPAT_MINOR; + default: + return 0; + } + } + return 0; +}
\ No newline at end of file diff --git a/host/tests/common/mock_ctrl_iface_impl.hpp b/host/tests/common/mock_ctrl_iface_impl.hpp new file mode 100644 index 000000000..8d2aafed6 --- /dev/null +++ b/host/tests/common/mock_ctrl_iface_impl.hpp @@ -0,0 +1,30 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + + +#ifndef INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP +#define INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP + +#include <uhd/rfnoc/constants.hpp> +#include <uhdlib/rfnoc/ctrl_iface.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/format.hpp> +#include <boost/bind.hpp> +#include <boost/make_shared.hpp> +#include <queue> + +class mock_ctrl_iface_impl : public uhd::rfnoc::ctrl_iface +{ + + uint64_t send_cmd_pkt( + const size_t addr, + const size_t data, + const bool readback=false, + const uint64_t timestamp=0 + ); +}; +#endif /* INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP */
\ No newline at end of file diff --git a/host/tests/common/mock_zero_copy.cpp b/host/tests/common/mock_zero_copy.cpp new file mode 100644 index 000000000..b1d384ec7 --- /dev/null +++ b/host/tests/common/mock_zero_copy.cpp @@ -0,0 +1,29 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + + +#include "mock_zero_copy.hpp" +#include <boost/shared_ptr.hpp> + +uhd::transport::managed_recv_buffer::sptr mock_zero_copy::get_recv_buff(double) { + if (_rx_mems.empty()) { + return uhd::transport::managed_recv_buffer::sptr(); // timeout + } + _mrbs.push_back(boost::make_shared<mock_mrb>()); + uhd::transport::managed_recv_buffer::sptr mrb = + _mrbs.back()->get_new(_rx_mems.front(), _rx_lens.front()); + _rx_mems.pop_front(); + _rx_lens.pop_front(); + return mrb; +} + +uhd::transport::managed_send_buffer::sptr mock_zero_copy::get_send_buff(double) { + _msbs.push_back(boost::make_shared<mock_msb>()); + _tx_mems.push_back( + boost::shared_array<uint8_t>(new uint8_t[SEND_BUFF_SIZE])); + _tx_lens.push_back(SEND_BUFF_SIZE); + return _msbs.back()->get_new(_tx_mems.back(), &_tx_lens.back()); +} diff --git a/host/tests/common/mock_zero_copy.hpp b/host/tests/common/mock_zero_copy.hpp new file mode 100644 index 000000000..838975129 --- /dev/null +++ b/host/tests/common/mock_zero_copy.hpp @@ -0,0 +1,88 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_MOCK_XPORT_HPP +#define INCLUDED_MOCK_XPORT_HPP + +#include <uhdlib/rfnoc/xports.hpp> +#include <uhd/transport/chdr.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <uhd/types/endianness.hpp> +#include <uhd/types/sid.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/make_shared.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/shared_array.hpp> +#include <list> +#include <vector> +/*********************************************************************** + * Transport mockups + **********************************************************************/ +/*! A single transport class that implements send() and recv() + * + * Tx and Rx are separate. We can access the other end of the FIFOs from + * this class. + */ +static constexpr size_t SEND_BUFF_SIZE = 1024; +static constexpr size_t RECV_BUFF_SIZE = 1024; + +/*********************************************************************** + * Dummy managed buffers for testing + **********************************************************************/ +class mock_msb : public uhd::transport::managed_send_buffer { + public: + void release(void) { /* nop */ + } + + sptr get_new(boost::shared_array<uint8_t> mem, size_t* len) { + _mem = mem; + return make(this, mem.get(), *len); + } + + private: + boost::shared_array<uint8_t> _mem; +}; + + +class mock_mrb : public uhd::transport::managed_recv_buffer { + public: + void release(void) { /* nop */ + } + + sptr get_new(boost::shared_array<uint8_t> mem, size_t len) { + _mem = mem; + return make(this, _mem.get(), len); + } + + private: + boost::shared_array<uint8_t> _mem; +}; + +class mock_zero_copy : public uhd::transport::zero_copy_if { + public: + typedef boost::shared_ptr<mock_zero_copy> sptr; + uhd::transport::managed_recv_buffer::sptr get_recv_buff(double); + + uhd::transport::managed_send_buffer::sptr get_send_buff(double); + + size_t get_num_recv_frames(void) const { return 1; } + size_t get_num_send_frames(void) const { return 1; } + size_t get_recv_frame_size(void) const { return RECV_BUFF_SIZE; } + size_t get_send_frame_size(void) const { return SEND_BUFF_SIZE; } + + private: + std::list<boost::shared_array<uint8_t>> _tx_mems; + std::list<size_t> _tx_lens; + + std::list<boost::shared_array<uint8_t>> _rx_mems; + std::list<size_t> _rx_lens; + + std::vector<boost::shared_ptr<mock_msb>> _msbs; + std::vector<boost::shared_ptr<mock_mrb>> _mrbs; +}; + +#endif /*INCLUDED_MOCK_XPORT_HPP*/
\ No newline at end of file diff --git a/host/tests/device3_test.cpp b/host/tests/device3_test.cpp index eb29d560f..658855f15 100644 --- a/host/tests/device3_test.cpp +++ b/host/tests/device3_test.cpp @@ -5,71 +5,53 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/property_tree.hpp> -#include <uhd/types/wb_iface.hpp> + +#include "mock_zero_copy.hpp" +#include "mock_ctrl_iface_impl.hpp" #include <uhd/device3.hpp> +#include <uhd/property_tree.hpp> #include <uhd/rfnoc/block_ctrl.hpp> #include <uhd/rfnoc/graph.hpp> -#include <uhd/rfnoc/constants.hpp> -#include <uhdlib/rfnoc/ctrl_iface.hpp> +#include <uhdlib/rfnoc/graph_impl.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> #include <boost/test/unit_test.hpp> #include <exception> #include <iostream> + + using namespace uhd; using namespace uhd::rfnoc; +using namespace uhd::transport::vrt; +using uhd::transport::managed_send_buffer; +using uhd::transport::managed_recv_buffer; -static const uint64_t TEST_NOC_ID = 0xAAAABBBBCCCCDDDD; static const sid_t TEST_SID0 = 0x00000200; // 0.0.2.0 static const sid_t TEST_SID1 = 0x00000210; // 0.0.2.F -// Pseudo-wb-iface -class pseudo_ctrl_iface_impl : public ctrl_iface -{ - public: - pseudo_ctrl_iface_impl() {} - virtual ~pseudo_ctrl_iface_impl() {} - - uint64_t send_cmd_pkt( - const size_t addr, - const size_t data, - const bool readback=false, - const uint64_t timestamp=0 - ) { - if (not readback) { - std::cout << str(boost::format("[PSEUDO] poke to addr: %016X, data == %016X") % addr % data) << std::endl; - } else { - std::cout << str(boost::format("[PSEUDO] peek64 to addr: %016X") % data) << std::endl; - switch (data) { - case SR_READBACK_REG_ID: - return TEST_NOC_ID; - case SR_READBACK_REG_FIFOSIZE: - return 0x000000000000000B; - case SR_READBACK_REG_USER: - return 0x0123456789ABCDEF; - case SR_READBACK_COMPAT: - return uhd::rfnoc::NOC_SHELL_COMPAT_MAJOR << 32 | - uhd::rfnoc::NOC_SHELL_COMPAT_MINOR; - default: - return 0; - } - } - return 0; - } -}; +uhd::both_xports_t make_mock_transport(const uhd::sid_t& tx_sid) { + uhd::both_xports_t xports; + xports.send_sid = tx_sid; + xports.recv_sid = tx_sid.reversed(); + xports.send_buff_size = SEND_BUFF_SIZE; + xports.recv_buff_size = RECV_BUFF_SIZE; + xports.send = boost::make_shared<mock_zero_copy>(); + xports.recv = xports.send; + return xports; +} -// Pseudo-device -class pseudo_device3_impl : public uhd::device3 +// Mock-device +class mock_device3_impl : public uhd::device3, public boost::enable_shared_from_this<mock_device3_impl> { public: - pseudo_device3_impl() + mock_device3_impl() { _tree = uhd::property_tree::make(); - _tree->create<std::string>("/name").set("Test Pseudo-Device3"); - + _tree->create<std::string>("/name").set("Test Mock-Device3"); // We can re-use this: std::map<size_t, ctrl_iface::sptr> ctrl_ifaces{ - {0, ctrl_iface::sptr(new pseudo_ctrl_iface_impl())} + {0, ctrl_iface::sptr(new mock_ctrl_iface_impl())} }; // Add two block controls: @@ -78,10 +60,9 @@ class pseudo_device3_impl : public uhd::device3 make_args.base_address = TEST_SID0.get_dst(); make_args.device_index = 0; make_args.tree = _tree; - std::cout << "[PSEUDO] Generating block controls 1/2:" << std::endl; + std::cout << "[MOCK] Generating block controls 1/2:" << std::endl; _rfnoc_block_ctrl.push_back( block_ctrl_base::make(make_args) ); - - std::cout << "[PSEUDO] Generating block controls 2/2:" << std::endl; + std::cout << "[MOCK] Generating block controls 2/2:" << std::endl; make_args.base_address = TEST_SID1.get_dst(); _rfnoc_block_ctrl.push_back( block_ctrl::make(make_args) ); } @@ -98,20 +79,38 @@ class pseudo_device3_impl : public uhd::device3 throw uhd::not_implemented_error(str(boost::format("%d %f") % async_metadata.channel % timeout)); } - rfnoc::graph::sptr create_graph(const std::string &) { return rfnoc::graph::sptr(); } + rfnoc::graph::sptr create_graph(const std::string &name) + { + sid_t async_sid(0); + async_sid.set_dst_addr(2); + auto async_xports = make_mock_transport(async_sid); + + auto async_msg_handler = uhd::rfnoc::async_msg_handler::make( + async_xports.recv, + async_xports.send, + async_xports.send_sid, + async_xports.endianness + ); + auto graph = boost::make_shared<uhd::rfnoc::graph_impl>( + name, + shared_from_this(), + async_msg_handler + ); + return graph; + } }; -device3::sptr make_pseudo_device() +device3::sptr make_mock_device() { - return device3::sptr(new pseudo_device3_impl()); + return device3::sptr(new mock_device3_impl()); } -class dummy_block_ctrl : public block_ctrl { +class mock_block_ctrl : public block_ctrl { int foo; }; BOOST_AUTO_TEST_CASE(test_device3) { - device3::sptr my_device = make_pseudo_device(); + device3::sptr my_device = make_mock_device(); std::cout << "Checking block 0..." << std::endl; BOOST_REQUIRE(my_device->find_blocks("Block").size()); @@ -130,8 +129,40 @@ BOOST_AUTO_TEST_CASE(test_device3) { BOOST_CHECK_EQUAL(block1->get_block_id(), "0/Block_1"); } + +BOOST_AUTO_TEST_CASE(test_device3_graph) { + auto my_device = make_mock_device(); + std::cout << "Start device3 test graph.." << std::endl; + std::cout << "Checking block 0..." << std::endl; + BOOST_REQUIRE(my_device->find_blocks("Block").size()); + std::cout << "Getting block 0..." << std::endl; + auto block0 = my_device->get_block_ctrl(my_device->find_blocks("Block")[0]); + BOOST_REQUIRE(block0); + BOOST_CHECK_EQUAL(block0->get_block_id(), "0/Block_0"); + + std::cout << "Checking block 1..." << std::endl; + BOOST_REQUIRE(my_device->has_block(block_id_t("0/Block_1"))); + + std::cout << "Getting block 1..." << std::endl; + auto block1 = my_device->get_block_ctrl(block_id_t("0/Block_1")); + BOOST_REQUIRE(block1); + BOOST_CHECK_EQUAL(block1->get_block_id(), "0/Block_1"); + std::cout << "Creating graph..." << std::endl; + auto graph = my_device->create_graph("test_graph"); + BOOST_CHECK(graph); + std::cout << "Connecting block_0 to block_1 ..." << std::endl; + graph->connect(block_id_t("0/Block_0"), 0, block_id_t("0/Block_1"), 0); + + BOOST_CHECK_EQUAL(block0->list_upstream_nodes().size(),0); + BOOST_CHECK_EQUAL(block0->list_downstream_nodes().size(),1); + BOOST_CHECK_EQUAL(block0->list_downstream_nodes()[0].lock()->unique_id(),"0/Block_1"); + BOOST_CHECK_EQUAL(block1->list_upstream_nodes().size(),1); + BOOST_CHECK_EQUAL(block1->list_downstream_nodes().size(),0); + BOOST_CHECK_EQUAL(block1->list_upstream_nodes()[0].lock()->unique_id(),"0/Block_0"); +} + BOOST_AUTO_TEST_CASE(test_device3_cast) { - device3::sptr my_device = make_pseudo_device(); + device3::sptr my_device = make_mock_device(); std::cout << "Getting block 0..." << std::endl; block_ctrl::sptr block0 = my_device->get_block_ctrl<block_ctrl>(block_id_t("0/Block_0")); @@ -144,10 +175,10 @@ BOOST_AUTO_TEST_CASE(test_device3_cast) { } BOOST_AUTO_TEST_CASE(test_device3_fail) { - device3::sptr my_device = make_pseudo_device(); + device3::sptr my_device = make_mock_device(); BOOST_CHECK(not my_device->has_block(block_id_t("0/FooBarBlock_0"))); - BOOST_CHECK(not my_device->has_block<dummy_block_ctrl>(block_id_t("0/Block_1"))); + BOOST_CHECK(not my_device->has_block<mock_block_ctrl>(block_id_t("0/Block_1"))); BOOST_CHECK(my_device->find_blocks("FooBarBlock").size() == 0); BOOST_CHECK(my_device->find_blocks<block_ctrl>("FooBarBlock").size() == 0); @@ -157,7 +188,7 @@ BOOST_AUTO_TEST_CASE(test_device3_fail) { uhd::lookup_error ); BOOST_REQUIRE_THROW( - my_device->get_block_ctrl<dummy_block_ctrl>(block_id_t("0/Block_1")), + my_device->get_block_ctrl<mock_block_ctrl>(block_id_t("0/Block_1")), uhd::lookup_error ); } |