mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-28 01:10:35 +08:00
306 lines
9.1 KiB
C++
306 lines
9.1 KiB
C++
/*
|
|
* Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <map>
|
|
#include <uavcan/protocol/dynamic_node_id_allocation_server.hpp>
|
|
#include "helpers.hpp"
|
|
|
|
class StorageBackend : public uavcan::IDynamicNodeIDStorageBackend
|
|
{
|
|
typedef std::map<String, String> Container;
|
|
Container container_;
|
|
|
|
bool fail_;
|
|
|
|
public:
|
|
StorageBackend()
|
|
: fail_(false)
|
|
{ }
|
|
|
|
virtual String get(const String& key) const
|
|
{
|
|
const Container::const_iterator it = container_.find(key);
|
|
if (it == container_.end())
|
|
{
|
|
return String();
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
virtual void set(const String& key, const String& value)
|
|
{
|
|
if (!fail_)
|
|
{
|
|
container_[key] = value;
|
|
}
|
|
}
|
|
|
|
void failOnSetCalls(bool really) { fail_ = really; }
|
|
|
|
void reset() { container_.clear(); }
|
|
|
|
unsigned getNumKeys() const { return unsigned(container_.size()); }
|
|
|
|
void print() const
|
|
{
|
|
for (Container::const_iterator it = container_.begin(); it != container_.end(); ++it)
|
|
{
|
|
std::cout << it->first.c_str() << "\t" << it->second.c_str() << std::endl;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
static const unsigned NumEntriesInStorageWithEmptyLog = 4; // last index + 3 items per log entry
|
|
|
|
|
|
TEST(DynamicNodeIDAllocationServer, MarshallingStorageDecorator)
|
|
{
|
|
StorageBackend st;
|
|
|
|
uavcan::dynamic_node_id_server_impl::MarshallingStorageDecorator marshaler(st);
|
|
|
|
uavcan::IDynamicNodeIDStorageBackend::String key;
|
|
|
|
/*
|
|
* uint32
|
|
*/
|
|
uint32_t u32 = 0;
|
|
|
|
key = "foo";
|
|
u32 = 0;
|
|
ASSERT_LE(0, marshaler.setAndGetBack(key, u32));
|
|
ASSERT_EQ(0, u32);
|
|
|
|
key = "bar";
|
|
u32 = 0xFFFFFFFF;
|
|
ASSERT_LE(0, marshaler.setAndGetBack(key, u32));
|
|
ASSERT_EQ(0xFFFFFFFF, u32);
|
|
ASSERT_LE(0, marshaler.get(key, u32));
|
|
ASSERT_EQ(0xFFFFFFFF, u32);
|
|
|
|
key = "foo";
|
|
ASSERT_LE(0, marshaler.get(key, u32));
|
|
ASSERT_EQ(0, u32);
|
|
|
|
key = "the_cake_is_a_lie";
|
|
ASSERT_GT(0, marshaler.get(key, u32));
|
|
ASSERT_EQ(0, u32);
|
|
|
|
/*
|
|
* uint8[16]
|
|
*/
|
|
uavcan::protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id array;
|
|
|
|
key = "a";
|
|
// Set zero
|
|
ASSERT_LE(0, marshaler.setAndGetBack(key, array));
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
{
|
|
ASSERT_EQ(0, array[i]);
|
|
}
|
|
|
|
// Make sure this will not be interpreted as uint32
|
|
ASSERT_GT(0, marshaler.get(key, u32));
|
|
ASSERT_EQ(0, u32);
|
|
|
|
// Set pattern
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
{
|
|
array[i] = uint8_t(i + 1);
|
|
}
|
|
ASSERT_LE(0, marshaler.setAndGetBack(key, array));
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
{
|
|
ASSERT_EQ(i + 1, array[i]);
|
|
}
|
|
|
|
// Set another pattern
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
{
|
|
array[i] = uint8_t(i | (i << 4));
|
|
}
|
|
ASSERT_LE(0, marshaler.setAndGetBack(key, array));
|
|
for (uint8_t i = 0; i < 16; i++)
|
|
{
|
|
ASSERT_EQ(uint8_t(i | (i << 4)), array[i]);
|
|
}
|
|
|
|
// Make sure uint32 cannot be interpreted as an array
|
|
key = "foo";
|
|
ASSERT_GT(0, marshaler.get(key, array));
|
|
|
|
// Nonexistent key
|
|
key = "the_cake_is_a_lie";
|
|
ASSERT_GT(0, marshaler.get(key, array));
|
|
}
|
|
|
|
|
|
TEST(DynamicNodeIDAllocationServer, LogInitialization)
|
|
{
|
|
// No log data in the storage - initializing empty log
|
|
{
|
|
StorageBackend storage;
|
|
uavcan::dynamic_node_id_server_impl::Log log(storage);
|
|
|
|
ASSERT_EQ(0, storage.getNumKeys());
|
|
ASSERT_LE(0, log.init());
|
|
ASSERT_EQ(NumEntriesInStorageWithEmptyLog, storage.getNumKeys());
|
|
ASSERT_EQ(0, log.getLastIndex());
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->term);
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->node_id);
|
|
ASSERT_EQ(uavcan::protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id(),
|
|
log.getEntryAtIndex(0)->unique_id);
|
|
}
|
|
// Nonempty storage, one item
|
|
{
|
|
StorageBackend storage;
|
|
uavcan::dynamic_node_id_server_impl::Log log(storage);
|
|
|
|
storage.set("log_last_index", "0");
|
|
ASSERT_LE(-uavcan::ErrFailure, log.init()); // Expected one entry, none found
|
|
ASSERT_EQ(1, storage.getNumKeys());
|
|
|
|
storage.set("log0_term", "0");
|
|
storage.set("log0_unique_id", "00000000000000000000000000000000");
|
|
storage.set("log0_node_id", "0");
|
|
ASSERT_LE(0, log.init()); // OK now
|
|
ASSERT_EQ(NumEntriesInStorageWithEmptyLog, storage.getNumKeys());
|
|
ASSERT_EQ(0, log.getLastIndex());
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->term);
|
|
}
|
|
// Nonempty storage, broken data
|
|
{
|
|
StorageBackend storage;
|
|
uavcan::dynamic_node_id_server_impl::Log log(storage);
|
|
|
|
storage.set("log_last_index", "foobar");
|
|
ASSERT_LE(-uavcan::ErrFailure, log.init()); // Bad value
|
|
|
|
storage.set("log_last_index", "128");
|
|
ASSERT_LE(-uavcan::ErrFailure, log.init()); // Bad value
|
|
|
|
storage.set("log_last_index", "0");
|
|
ASSERT_LE(-uavcan::ErrFailure, log.init()); // No log items
|
|
ASSERT_EQ(1, storage.getNumKeys());
|
|
|
|
storage.set("log0_term", "0");
|
|
storage.set("log0_unique_id", "00000000000000000000000000000000");
|
|
storage.set("log0_node_id", "128"); // Bad value (127 max)
|
|
ASSERT_LE(-uavcan::ErrFailure, log.init()); // Failed
|
|
ASSERT_EQ(0, log.getLastIndex());
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->term);
|
|
ASSERT_EQ(4, storage.getNumKeys());
|
|
}
|
|
// Nonempty storage, many items
|
|
{
|
|
StorageBackend storage;
|
|
uavcan::dynamic_node_id_server_impl::Log log(storage);
|
|
|
|
storage.set("log_last_index", "1"); // 2 items - 0, 1
|
|
storage.set("log0_term", "0");
|
|
storage.set("log0_unique_id", "00000000000000000000000000000000");
|
|
storage.set("log0_node_id", "0");
|
|
storage.set("log1_term", "1");
|
|
storage.set("log1_unique_id", "0123456789abcdef0123456789abcdef");
|
|
storage.set("log1_node_id", "127");
|
|
|
|
ASSERT_LE(0, log.init()); // OK now
|
|
ASSERT_EQ(7, storage.getNumKeys());
|
|
ASSERT_EQ(1, log.getLastIndex());
|
|
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->term);
|
|
ASSERT_EQ(0, log.getEntryAtIndex(0)->node_id);
|
|
ASSERT_EQ(uavcan::protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id(),
|
|
log.getEntryAtIndex(0)->unique_id);
|
|
|
|
ASSERT_EQ(1, log.getEntryAtIndex(1)->term);
|
|
ASSERT_EQ(127, log.getEntryAtIndex(1)->node_id);
|
|
uavcan::protocol::dynamic_node_id::server::Entry::FieldTypes::unique_id uid;
|
|
uid[0] = 0x01;
|
|
uid[1] = 0x23;
|
|
uid[2] = 0x45;
|
|
uid[3] = 0x67;
|
|
uid[4] = 0x89;
|
|
uid[5] = 0xab;
|
|
uid[6] = 0xcd;
|
|
uid[7] = 0xef;
|
|
uavcan::copy(uid.begin(), uid.begin() + 8, uid.begin() + 8);
|
|
ASSERT_EQ(uid, log.getEntryAtIndex(1)->unique_id);
|
|
}
|
|
}
|
|
|
|
|
|
TEST(DynamicNodeIDAllocationServer, LogAppend)
|
|
{
|
|
StorageBackend storage;
|
|
uavcan::dynamic_node_id_server_impl::Log log(storage);
|
|
|
|
ASSERT_EQ(0, storage.getNumKeys());
|
|
ASSERT_LE(0, log.init());
|
|
storage.print();
|
|
ASSERT_EQ(NumEntriesInStorageWithEmptyLog, storage.getNumKeys());
|
|
|
|
/*
|
|
* Entry at the index 0 always exists, and it's always zero-initialized.
|
|
*/
|
|
ASSERT_EQ("0", storage.get("log_last_index"));
|
|
ASSERT_EQ("0", storage.get("log0_term"));
|
|
ASSERT_EQ("00000000000000000000000000000000", storage.get("log0_unique_id"));
|
|
ASSERT_EQ("0", storage.get("log0_node_id"));
|
|
|
|
/*
|
|
* Adding one entry to the log, making sure it appears in the storage
|
|
*/
|
|
uavcan::protocol::dynamic_node_id::server::Entry entry;
|
|
entry.term = 1;
|
|
entry.node_id = 1;
|
|
entry.unique_id[0] = 1;
|
|
ASSERT_LE(0, log.append(entry));
|
|
|
|
ASSERT_EQ("1", storage.get("log_last_index"));
|
|
ASSERT_EQ("1", storage.get("log1_term"));
|
|
ASSERT_EQ("01000000000000000000000000000000", storage.get("log1_unique_id"));
|
|
ASSERT_EQ("1", storage.get("log1_node_id"));
|
|
|
|
ASSERT_EQ(1, log.getLastIndex());
|
|
ASSERT_TRUE(entry == *log.getEntryAtIndex(1));
|
|
|
|
/*
|
|
* Adding another entry while storage is failing
|
|
*/
|
|
storage.failOnSetCalls(true);
|
|
|
|
ASSERT_EQ(7, storage.getNumKeys());
|
|
|
|
entry.term = 2;
|
|
entry.node_id = 2;
|
|
entry.unique_id[0] = 2;
|
|
ASSERT_GT(0, log.append(entry));
|
|
|
|
ASSERT_EQ(7, storage.getNumKeys()); // No new entries, we failed
|
|
|
|
ASSERT_EQ(1, log.getLastIndex());
|
|
|
|
/*
|
|
* Making sure append() fails when the log is full
|
|
*/
|
|
storage.failOnSetCalls(false);
|
|
|
|
while (log.getLastIndex() < (log.Capacity - 1))
|
|
{
|
|
ASSERT_LE(0, log.append(entry));
|
|
ASSERT_TRUE(entry == *log.getEntryAtIndex(log.getLastIndex()));
|
|
|
|
entry.term += 1;
|
|
entry.node_id = uint8_t(entry.node_id + 1U);
|
|
entry.unique_id[0] = uint8_t(entry.unique_id[0] + 1U);
|
|
}
|
|
|
|
ASSERT_GT(0, log.append(entry)); // Failing because full
|
|
|
|
storage.print();
|
|
}
|