Implemented TransferBufferManager

This commit is contained in:
Pavel Kirienko
2014-02-06 00:08:51 +04:00
parent 690e0257dc
commit 261dd546cd
3 changed files with 398 additions and 5 deletions
+152 -5
View File
@@ -4,6 +4,7 @@
#include <algorithm>
#include <gtest/gtest.h>
#include <memory>
#include <uavcan/internal/transport/transfer_buffer.hpp>
static const std::string TEST_DATA =
@@ -28,7 +29,8 @@ static void fill(const T a, int value)
a[i] = value;
}
static bool matchAgainstTestData(const uavcan::TransferBufferBase& tbb, unsigned int offset, int len = -1)
static bool matchAgainst(const std::string& data, const uavcan::TransferBufferBase& tbb,
unsigned int offset = 0, int len = -1)
{
uint8_t local_buffer[1024];
fill(local_buffer, 0);
@@ -39,7 +41,7 @@ static bool matchAgainstTestData(const uavcan::TransferBufferBase& tbb, unsigned
const int res = tbb.read(offset, local_buffer, sizeof(local_buffer));
if (res < 0)
{
std::cout << "matchAgainstTestData(): res " << res << std::endl;
std::cout << "matchAgainst(): res " << res << std::endl;
return false;
}
len = res;
@@ -49,23 +51,28 @@ static bool matchAgainstTestData(const uavcan::TransferBufferBase& tbb, unsigned
const int res = tbb.read(offset, local_buffer, len);
if (res != len)
{
std::cout << "matchAgainstTestData(): res " << res << " expected " << len << std::endl;
std::cout << "matchAgainst(): res " << res << " expected " << len << std::endl;
return false;
}
}
const bool equals = std::equal(local_buffer, local_buffer + len, TEST_DATA.begin() + offset);
const bool equals = std::equal(local_buffer, local_buffer + len, data.begin() + offset);
if (!equals)
{
std::cout
<< "local_buffer:\n\t" << local_buffer
<< std::endl;
std::cout
<< "test_data:\n\t" << std::string(TEST_DATA.begin() + offset, TEST_DATA.begin() + offset + len)
<< "test_data:\n\t" << std::string(data.begin() + offset, data.begin() + offset + len)
<< std::endl;
}
return equals;
}
static bool matchAgainstTestData(const uavcan::TransferBufferBase& tbb, unsigned int offset, int len = -1)
{
return matchAgainst(TEST_DATA, tbb, offset, len);
}
TEST(TransferBuffer, TestDataValidation)
{
ASSERT_LE(4, TEST_DATA.length() / uavcan::MEM_POOL_BLOCK_SIZE);
@@ -188,3 +195,143 @@ TEST(DynamicTransferBuffer, Basic)
buf.~DynamicTransferBuffer();
ASSERT_EQ(0, pool.getNumUsedBlocks());
}
static const std::string MGR_TEST_DATA[4] =
{
"I thought you would cry out again \'don\'t speak of it, leave off.\'\" Raskolnikov gave a laugh, but rather a "
"forced one. \"What, silence again?\" he asked a minute later. \"We must talk about something, you know. ",
"It would be interesting for me to know how you would decide a certain \'problem\' as Lebeziatnikov would say.\" "
"(He was beginning to lose the thread.) \"No, really, I am serious. Imagine, Sonia, that you had known all ",
"Luzhin\'s intentions beforehand. Known, that is, for a fact, that they would be the ruin of Katerina Ivanovna "
"and the children and yourself thrown in--since you don\'t count yourself for anything--Polenka too... for ",
"she\'ll go the same way. Well, if suddenly it all depended on your decision whether he or they should go on "
"living, that is whether Luzhin should go on living and doing wicked things, or Katerina Ivanovna should die? "
"How would you decide which of them was to die? I ask you?"
};
static const int MGR_STATIC_BUFFER_SIZE = 100;
TEST(TransferBufferManager, TestDataValidation)
{
for (unsigned int i = 0; i < sizeof(MGR_TEST_DATA) / sizeof(MGR_TEST_DATA[0]); i++)
{
ASSERT_LT(MGR_STATIC_BUFFER_SIZE, MGR_TEST_DATA[i].length());
}
}
static int fillTestData(const std::string& data, uavcan::TransferBufferBase* tbb)
{
return tbb->write(0, reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
}
TEST(TransferBufferManager, Basic)
{
using uavcan::TransferBufferManager;
using uavcan::TransferBufferBase;
static const int POOL_BLOCKS = 8;
uavcan::PoolAllocator<uavcan::MEM_POOL_BLOCK_SIZE * POOL_BLOCKS, uavcan::MEM_POOL_BLOCK_SIZE> pool;
uavcan::PoolManager<1> poolmgr;
poolmgr.addPool(&pool);
typedef TransferBufferManager<MGR_STATIC_BUFFER_SIZE, 2> TransferBufferManagerType;
std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(&poolmgr));
// Empty
ASSERT_FALSE(mgr->access(0));
ASSERT_FALSE(mgr->access(uavcan::NODE_ID_MAX));
TransferBufferBase* tbb = NULL;
// Static 0
ASSERT_TRUE((tbb = mgr->create(0)));
tbb->setUpdateTimestamp(1234);
ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
ASSERT_EQ(1, mgr->getNumStaticBuffers());
// Static 1
ASSERT_TRUE((tbb = mgr->create(1)));
tbb->setUpdateTimestamp(2345);
ASSERT_EQ(MGR_STATIC_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(0, mgr->getNumDynamicBuffers());
ASSERT_EQ(0, pool.getNumUsedBlocks());
// Dynamic 0
ASSERT_TRUE((tbb = mgr->create(2)));
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Empty dynamic buffer occupies one block
tbb->setUpdateTimestamp(3456);
ASSERT_EQ(MGR_TEST_DATA[2].length(), fillTestData(MGR_TEST_DATA[2], tbb));
ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(1, mgr->getNumDynamicBuffers());
ASSERT_LT(1, pool.getNumUsedBlocks());
std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
// Dynamic 2
ASSERT_TRUE((tbb = mgr->create(127)));
ASSERT_EQ(0, pool.getNumFreeBlocks()); // The test assumes that the memory must be exhausted now
tbb->setUpdateTimestamp(4567);
ASSERT_EQ(0, fillTestData(MGR_TEST_DATA[3], tbb));
ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
// Dynamic 3 - will fail due to OOM
ASSERT_FALSE((tbb = mgr->create(64)));
ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
// Making sure all buffers contain proper data
ASSERT_TRUE((tbb = mgr->access(0)));
ASSERT_EQ(1234, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[0], *tbb));
ASSERT_TRUE((tbb = mgr->access(1)));
ASSERT_EQ(2345, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[1], *tbb));
ASSERT_TRUE((tbb = mgr->access(2)));
ASSERT_EQ(3456, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
ASSERT_TRUE((tbb = mgr->access(127)));
ASSERT_EQ(4567, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
// Freeing one static buffer; one dynamic must migrate
mgr->remove(1);
ASSERT_FALSE(mgr->access(1));
ASSERT_EQ(2, mgr->getNumStaticBuffers());
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // One migrated to the static
ASSERT_LT(0, pool.getNumFreeBlocks());
// Cleanup must remove NodeID 0 due to low timestamp; migration should fail due to oversized data
mgr->cleanup(2000);
ASSERT_FALSE(mgr->access(0));
ASSERT_EQ(1, mgr->getNumStaticBuffers());
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // Migration failed
// At this time we have the following NodeID: 2, 127
ASSERT_TRUE((tbb = mgr->access(2)));
ASSERT_EQ(3456, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[2], *tbb));
ASSERT_TRUE((tbb = mgr->access(127)));
ASSERT_EQ(4567, tbb->getUpdateTimestamp());
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
// These were deleted: 0, 1
ASSERT_FALSE(mgr->access(1));
ASSERT_FALSE(mgr->access(0));
// Deleting the object; all memory must be freed
ASSERT_NE(0, pool.getNumUsedBlocks());
mgr.reset();
ASSERT_EQ(0, pool.getNumUsedBlocks());
}