From 69eadee72bda461f1deec59f4799e10b853e82f6 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 18 Feb 2014 16:26:48 +0400 Subject: [PATCH] Dispatcher reception test --- libuavcan/test/common.hpp | 6 +- libuavcan/test/transport/dispatcher.cpp | 184 ++++++++++++++++++ .../test/transport/transfer_listener.cpp | 14 +- .../test/transport/transfer_test_helpers.hpp | 10 +- 4 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 libuavcan/test/transport/dispatcher.cpp diff --git a/libuavcan/test/common.hpp b/libuavcan/test/common.hpp index e93efccfb1..b3b9ab67cc 100644 --- a/libuavcan/test/common.hpp +++ b/libuavcan/test/common.hpp @@ -14,9 +14,9 @@ public: uint64_t monotonic; uint64_t utc; - SystemClockMock() - : monotonic(0) - , utc(0) + SystemClockMock(uint64_t initial = 0) + : monotonic(initial) + , utc(initial) { } void advance(uint64_t usec) diff --git a/libuavcan/test/transport/dispatcher.cpp b/libuavcan/test/transport/dispatcher.cpp new file mode 100644 index 0000000000..2ce8fa81a3 --- /dev/null +++ b/libuavcan/test/transport/dispatcher.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 Pavel Kirienko + */ + +#include +#include +#include "transfer_test_helpers.hpp" +#include "can/iface_mock.hpp" +#include + + +class DispatcherTransferEmulator : public IncomingTransferEmulatorBase +{ + CanDriverMock& target_; + +public: + DispatcherTransferEmulator(CanDriverMock& target, uavcan::NodeID dst_node_id = 127) + : IncomingTransferEmulatorBase(dst_node_id) + , target_(target) + { } + + void sendOneFrame(const uavcan::RxFrame& frame) + { + CanIfaceMock* const iface = static_cast(target_.getIface(frame.getIfaceIndex())); + EXPECT_TRUE(iface); + if (iface) + iface->pushRx(frame); + } +}; + + +static uavcan::DataTypeDescriptor makeDataType(uavcan::DataTypeKind kind, uint16_t id) +{ + uavcan::DataTypeDescriptor dtd(kind, id, uavcan::DataTypeHash()); + for (int i = 0; i < uavcan::DataTypeHash::NUM_BYTES; i += 2) + { + dtd.hash.value[i] = id & 0xFF; + dtd.hash.value[i + 1] = id >> 8; + } + return dtd; +} + + +static const uavcan::NodeID SELF_NODE_ID(64); + + +TEST(Dispatcher, Reception) +{ + uavcan::PoolAllocator pool; + uavcan::PoolManager<1> poolmgr; + poolmgr.addPool(&pool); + + SystemClockMock clockmock(100); + CanDriverMock driver(2, clockmock); + + uavcan::OutgoingTransferRegistry<8> out_trans_reg(&poolmgr); + + uavcan::Dispatcher dispatcher(&driver, &poolmgr, &clockmock, &out_trans_reg, SELF_NODE_ID); + + DispatcherTransferEmulator emulator(driver, SELF_NODE_ID); + + /* + * Test environment + */ + static const uavcan::DataTypeDescriptor TYPES[4] = + { + makeDataType(uavcan::DATA_TYPE_KIND_MESSAGE, 1), + makeDataType(uavcan::DATA_TYPE_KIND_MESSAGE, 2), + makeDataType(uavcan::DATA_TYPE_KIND_SERVICE, 1), + makeDataType(uavcan::DATA_TYPE_KIND_SERVICE, 1) + }; + + typedef TestSubscriber<512, 2, 2> Subscriber; + typedef std::auto_ptr SubscriberPtr; + static const int NUM_SUBSCRIBERS = 6; + SubscriberPtr subscribers[NUM_SUBSCRIBERS] = + { + SubscriberPtr(new Subscriber(TYPES + 0, &poolmgr)), // msg + SubscriberPtr(new Subscriber(TYPES + 0, &poolmgr)), // msg // Two similar, yes + SubscriberPtr(new Subscriber(TYPES + 1, &poolmgr)), // msg + SubscriberPtr(new Subscriber(TYPES + 2, &poolmgr)), // srv + SubscriberPtr(new Subscriber(TYPES + 3, &poolmgr)), // srv + SubscriberPtr(new Subscriber(TYPES + 3, &poolmgr)) // srv // Repeat again + }; + + static const std::string DATA[6] = + { + "Yes, man is mortal, but that would be only half the trouble. " + "The worst of it is that he's sometimes unexpectedly mortal - there's the trick!", + + "In fact, I'm beginning to fear that this confusion will go on for a long time. " + "And all because he writes down what I said incorrectly.", + + "I had the pleasure of meeting that young man at the Patriarch's Ponds. " + "He almost drove me mad myself, proving to me that I don't exist.", + + "He was a dreamer, a thinker, a speculative philosopher... or, as his wife would have it, an idiot.", + + "The only way to get ideas for stories is to drink way too much coffee and buy a desk that doesn't " + "collapse when you beat your head against it", + + "" + }; + + const Transfer transfers[9] = + { + emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 10, DATA[0], TYPES[0]), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 11, DATA[1], TYPES[1]), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_SERVICE_REQUEST, 12, DATA[2], TYPES[2]), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_SERVICE_RESPONSE, 13, DATA[3], TYPES[3]), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 14, DATA[4], TYPES[0]), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 15, DATA[5], TYPES[1]), + // Wrongly addressed: + emulator.makeTransfer(uavcan::TRANSFER_TYPE_SERVICE_RESPONSE, 10, DATA[0], TYPES[3], 100), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_SERVICE_REQUEST, 11, DATA[1], TYPES[2], 101), + emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 12, DATA[2], TYPES[1], 102) + }; + + /* + * Sending the transfers + */ + ASSERT_TRUE(dispatcher.registerMessageListener(subscribers[0].get())); + ASSERT_TRUE(dispatcher.registerMessageListener(subscribers[1].get())); + ASSERT_TRUE(dispatcher.registerMessageListener(subscribers[2].get())); + ASSERT_TRUE(dispatcher.registerServiceRequestListener(subscribers[3].get())); + ASSERT_TRUE(dispatcher.registerServiceResponseListener(subscribers[4].get())); + ASSERT_TRUE(dispatcher.registerServiceResponseListener(subscribers[5].get())); + + // Multiple service request listeners are not allowed + ASSERT_FALSE(dispatcher.registerServiceRequestListener(subscribers[3].get())); + + for (int i = 0; i < NUM_SUBSCRIBERS; i++) + ASSERT_TRUE(subscribers[i]->isEmpty()); + + emulator.send(transfers); + emulator.send(transfers); // Just for fun, they will be ignored anyway. + + while (true) + { + const int res = dispatcher.spin(0); + ASSERT_LE(0, res); + clockmock.advance(100); + if (res == 0) + break; + } + + /* + * Matching. + * Expected reception order per subsciber: + * 0: 0, 4 + * 1: 0, 4 + * 2: 5, 1 + * 3: 2 + * 4: 3 + * 5: 3 + */ + ASSERT_TRUE(subscribers[0]->matchAndPop(transfers[0])); + ASSERT_TRUE(subscribers[0]->matchAndPop(transfers[4])); + + ASSERT_TRUE(subscribers[1]->matchAndPop(transfers[0])); + ASSERT_TRUE(subscribers[1]->matchAndPop(transfers[4])); + + ASSERT_TRUE(subscribers[2]->matchAndPop(transfers[5])); + ASSERT_TRUE(subscribers[2]->matchAndPop(transfers[1])); + + ASSERT_TRUE(subscribers[3]->matchAndPop(transfers[2])); + + ASSERT_TRUE(subscribers[4]->matchAndPop(transfers[3])); + + ASSERT_TRUE(subscribers[5]->matchAndPop(transfers[3])); + + for (int i = 0; i < NUM_SUBSCRIBERS; i++) + ASSERT_TRUE(subscribers[i]->isEmpty()); + + /* + * Unregistering all transfers + */ + dispatcher.unregisterMessageListener(subscribers[0].get()); + dispatcher.unregisterMessageListener(subscribers[1].get()); + dispatcher.unregisterMessageListener(subscribers[2].get()); + dispatcher.unregisterServiceRequestListener(subscribers[3].get()); + dispatcher.unregisterServiceResponseListener(subscribers[4].get()); + dispatcher.unregisterServiceResponseListener(subscribers[5].get()); +} diff --git a/libuavcan/test/transport/transfer_listener.cpp b/libuavcan/test/transport/transfer_listener.cpp index 199b904dc7..ced48c02d1 100644 --- a/libuavcan/test/transport/transfer_listener.cpp +++ b/libuavcan/test/transport/transfer_listener.cpp @@ -6,13 +6,13 @@ #include "transfer_test_helpers.hpp" -class Emulator : public IncomingTransferEmulatorBase +class TransferListenerEmulator : public IncomingTransferEmulatorBase { uavcan::TransferListenerBase& target_; const uavcan::DataTypeDescriptor data_type_; public: - Emulator(uavcan::TransferListenerBase& target, const uavcan::DataTypeDescriptor& type, + TransferListenerEmulator(uavcan::TransferListenerBase& target, const uavcan::DataTypeDescriptor& type, uavcan::NodeID dst_node_id = 127) : IncomingTransferEmulatorBase(dst_node_id) , target_(target) @@ -59,7 +59,7 @@ TEST(TransferListener, BasicMFT) "BEWARE JET BLAST" }; - Emulator emulator(subscriber, type); + TransferListenerEmulator emulator(subscriber, type); const Transfer transfers[] = { emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 1, DATA[0]), @@ -97,7 +97,7 @@ TEST(TransferListener, CrcFailure) /* * Generating transfers with damaged payload (CRC is not valid) */ - Emulator emulator(subscriber, type); + TransferListenerEmulator emulator(subscriber, type); const Transfer tr_mft = emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 42, "123456789abcdefghik"); const Transfer tr_sft = emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 11, "abcd"); @@ -139,7 +139,7 @@ TEST(TransferListener, BasicSFT) uavcan::PoolManager<1> poolmgr; // No dynamic memory. At all. TestSubscriber<0, 0, 5> subscriber(&type, &poolmgr); // Max buf size is 0, i.e. SFT-only - Emulator emulator(subscriber, type); + TransferListenerEmulator emulator(subscriber, type); const Transfer transfers[] = { emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 1, "123"), @@ -179,7 +179,7 @@ TEST(TransferListener, Cleanup) /* * Generating transfers */ - Emulator emulator(subscriber, type); + TransferListenerEmulator emulator(subscriber, type); const Transfer tr_mft = emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST, 42, "123456789abcdefghik"); const Transfer tr_sft = emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 11, "abcd"); @@ -234,7 +234,7 @@ TEST(TransferListener, MaximumTransferLength) static const std::string DATA_OK(uavcan::MAX_TRANSFER_PAYLOAD_LEN, 'z'); - Emulator emulator(subscriber, type); + TransferListenerEmulator emulator(subscriber, type); const Transfer transfers[] = { emulator.makeTransfer(uavcan::TRANSFER_TYPE_MESSAGE_UNICAST, 1, DATA_OK), diff --git a/libuavcan/test/transport/transfer_test_helpers.hpp b/libuavcan/test/transport/transfer_test_helpers.hpp index c1edc7b8f6..8a854d8dad 100644 --- a/libuavcan/test/transport/transfer_test_helpers.hpp +++ b/libuavcan/test/transport/transfer_test_helpers.hpp @@ -67,11 +67,11 @@ struct Transfer { return (ts_monotonic == rhs.ts_monotonic) && - (ts_utc == rhs.ts_utc) && + ((ts_utc && rhs.ts_utc) ? (ts_utc == rhs.ts_utc) : true) && (transfer_type == rhs.transfer_type) && (transfer_id == rhs.transfer_id) && (src_node_id == rhs.src_node_id) && - (dst_node_id.isValid() ? (dst_node_id == rhs.dst_node_id) : true) && + ((dst_node_id.isValid() && rhs.dst_node_id.isValid()) ? (dst_node_id == rhs.dst_node_id) : true) && (data_type == rhs.data_type) && (payload == rhs.payload); } @@ -227,11 +227,13 @@ public: virtual ~IncomingTransferEmulatorBase() { } Transfer makeTransfer(uavcan::TransferType transfer_type, uint8_t source_node_id, const std::string& payload, - const uavcan::DataTypeDescriptor& type) + const uavcan::DataTypeDescriptor& type, + uavcan::NodeID dst_node_id_override = uavcan::NodeID()) { ts_ += 100; const uavcan::NodeID dst_node_id = (transfer_type == uavcan::TRANSFER_TYPE_MESSAGE_BROADCAST) - ? uavcan::NodeID::BROADCAST : dst_node_id_; + ? uavcan::NodeID::BROADCAST + : (dst_node_id_override.isValid() ? dst_node_id_override : dst_node_id_); const Transfer tr(ts_, ts_ + 1000000000ul, transfer_type, tid_, source_node_id, dst_node_id, payload, type); tid_.increment(); return tr;