New upstream version 8.1.0
This commit is contained in:
251
common/tests/TestBitStore.cpp
Normal file
251
common/tests/TestBitStore.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
#include <common/toolkit/BitStore.h>
|
||||
#include <common/toolkit/Random.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
#define TESTBITSTORE_MAX_BITSTORE_SIZE 242
|
||||
#define TESTBITSTORE_RANDOM_VALUES_COUNT 75
|
||||
|
||||
struct TestBitStoreBlockCountResult
|
||||
{
|
||||
int blockCount; // the needed blockCount
|
||||
};
|
||||
|
||||
/**
|
||||
* The number of blocks required to store a certain number of bits.
|
||||
*/
|
||||
struct TestBitStoreBlockCountResult const __TESTBITSTORE_BLOCK_COUNT_RESULTS[] =
|
||||
{
|
||||
{1 + ( ( (32*1)-1) / BitStore::LIMB_SIZE) }, // result for bits 1 to 32
|
||||
{1 + ( ( (32*2)-1) / BitStore::LIMB_SIZE) }, // result for bits 33 to 64
|
||||
{1 + ( ( (32*3)-1) / BitStore::LIMB_SIZE) }, // result for bits 65 to 96
|
||||
{1 + ( ( (32*4)-1) / BitStore::LIMB_SIZE) }, // result for bits 97 to 128
|
||||
{1 + ( ( (32*5)-1) / BitStore::LIMB_SIZE) }, // result for bits 129 to 160
|
||||
{1 + ( ( (32*6)-1) / BitStore::LIMB_SIZE) }, // result for bits 161 to 192
|
||||
{1 + ( ( (32*7)-1) / BitStore::LIMB_SIZE) }, // result for bits 193 to 224
|
||||
{1 + ( ( (32*8)-1) / BitStore::LIMB_SIZE) }, // result for bits 125 to 256
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TestBitStore : public ::testing::Test {
|
||||
protected:
|
||||
BitStore::limb_type& lowerBits(BitStore& store) { return store.lowerBits; }
|
||||
BitStore::limb_type* higherBits(BitStore& store) { return store.higherBits.get(); }
|
||||
};
|
||||
|
||||
TEST_F(TestBitStore, calculateBitBlockCount)
|
||||
{
|
||||
unsigned blockCount;
|
||||
unsigned resultIndex = 0;
|
||||
|
||||
for(int size = 1; size < TESTBITSTORE_MAX_BITSTORE_SIZE; size++)
|
||||
{
|
||||
if(size < 33)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[0].blockCount;
|
||||
else
|
||||
if(size < 65)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[1].blockCount;
|
||||
else
|
||||
if(size < 97)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[2].blockCount;
|
||||
else
|
||||
if(size < 129)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[3].blockCount;
|
||||
else
|
||||
if(size < 161)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[4].blockCount;
|
||||
else
|
||||
if(size < 193)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[5].blockCount;
|
||||
else
|
||||
if(size < 225)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[6].blockCount;
|
||||
else
|
||||
if(size < 257)
|
||||
resultIndex = __TESTBITSTORE_BLOCK_COUNT_RESULTS[7].blockCount;
|
||||
|
||||
blockCount = BitStore::calculateBitBlockCount(size);
|
||||
|
||||
EXPECT_EQ(blockCount, resultIndex);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestBitStore, setSizeAndReset)
|
||||
{
|
||||
const int initValue = 32896;
|
||||
int size = 1;
|
||||
bool reverse = false;
|
||||
bool finished = false;
|
||||
|
||||
BitStore store(size);
|
||||
|
||||
while(finished)
|
||||
{
|
||||
int higherBitsBlockCount = BitStore::calculateBitBlockCount(size) - 1;
|
||||
|
||||
//set some data to the bit store
|
||||
lowerBits(store) = initValue;
|
||||
|
||||
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
|
||||
{
|
||||
higherBits(store)[blockIndex] = initValue;
|
||||
}
|
||||
|
||||
// set the new size and reset all values
|
||||
store.setSize(size);
|
||||
store.clearBits();
|
||||
|
||||
//check the lower bits
|
||||
EXPECT_EQ(lowerBits(store), 0u);
|
||||
|
||||
//check the higher bits
|
||||
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
|
||||
EXPECT_EQ(higherBits(store)[blockIndex], 0u);
|
||||
|
||||
if(size == TESTBITSTORE_MAX_BITSTORE_SIZE)
|
||||
reverse = true;
|
||||
|
||||
if(reverse)
|
||||
size--;
|
||||
else
|
||||
size++;
|
||||
|
||||
//
|
||||
|
||||
// finish test or set the new size
|
||||
if(reverse && size == 0)
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestBitStore, getter)
|
||||
{
|
||||
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
|
||||
|
||||
// check the getter for all bits
|
||||
for(int index = 0; index < TESTBITSTORE_MAX_BITSTORE_SIZE; index++)
|
||||
{
|
||||
// set a bit
|
||||
int blockIndexOfBit = index / BitStore::LIMB_SIZE;
|
||||
BitStore::limb_type value = 1UL << (index % BitStore::LIMB_SIZE);
|
||||
|
||||
if(blockIndexOfBit == 0)
|
||||
lowerBits(store) = value;
|
||||
else
|
||||
higherBits(store)[blockIndexOfBit - 1] = value;
|
||||
|
||||
// check if all bits contain the correct value
|
||||
for(int testIndex = 0; testIndex < TESTBITSTORE_MAX_BITSTORE_SIZE; testIndex++)
|
||||
{
|
||||
if(testIndex != index)
|
||||
EXPECT_FALSE(store.getBitNonAtomic(testIndex));
|
||||
else
|
||||
EXPECT_TRUE(store.getBitNonAtomic(testIndex));
|
||||
}
|
||||
|
||||
store.clearBits();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestBitStore, setter)
|
||||
{
|
||||
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
|
||||
int higherBitsBlockCount = BitStore::calculateBitBlockCount(TESTBITSTORE_MAX_BITSTORE_SIZE) - 1;
|
||||
|
||||
// check the setter for all bits
|
||||
for(int index = 0; index < TESTBITSTORE_MAX_BITSTORE_SIZE; index++)
|
||||
{
|
||||
store.setBit(index, true);
|
||||
|
||||
// check if all bit blocks contains the correct value
|
||||
int blockIndexOfBit = index / BitStore::LIMB_SIZE;
|
||||
BitStore::limb_type neededValue = 1UL << (index % BitStore::LIMB_SIZE);
|
||||
|
||||
// check lower bit block
|
||||
if(blockIndexOfBit == 0)
|
||||
EXPECT_EQ(lowerBits(store), neededValue);
|
||||
else
|
||||
EXPECT_EQ(lowerBits(store), 0u);
|
||||
|
||||
// check higher bit blocks
|
||||
for(int blockIndex = 0; blockIndex < higherBitsBlockCount; blockIndex++)
|
||||
{
|
||||
if(blockIndex != (blockIndexOfBit - 1) )
|
||||
EXPECT_EQ(higherBits(store)[blockIndex], 0u);
|
||||
else
|
||||
EXPECT_EQ(higherBits(store)[blockIndex], neededValue);
|
||||
}
|
||||
|
||||
store.clearBits();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkSerialization(BitStore* store)
|
||||
{
|
||||
BitStore secondStore;
|
||||
|
||||
unsigned serialLen;
|
||||
{
|
||||
Serializer ser;
|
||||
ser % *store;
|
||||
serialLen = ser.size();
|
||||
}
|
||||
|
||||
boost::scoped_array<char> buf(new char[serialLen]);
|
||||
|
||||
unsigned serializationRes;
|
||||
{
|
||||
Serializer ser(buf.get(), serialLen);
|
||||
ser % *store;
|
||||
serializationRes = ser.size();
|
||||
}
|
||||
|
||||
ASSERT_EQ(serialLen, serializationRes);
|
||||
|
||||
unsigned deserLen;
|
||||
bool success;
|
||||
{
|
||||
Deserializer des(buf.get(), serialLen);
|
||||
des % secondStore;
|
||||
deserLen = des.size();
|
||||
success = des.good();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(success) << "BitStore deserialization failed.";
|
||||
EXPECT_EQ(deserLen, serialLen);
|
||||
EXPECT_EQ(*store, secondStore);
|
||||
}
|
||||
|
||||
TEST_F(TestBitStore, serialization)
|
||||
{
|
||||
// check serialization for different BitStore size
|
||||
for(int size = 1; size <= TESTBITSTORE_MAX_BITSTORE_SIZE; size++)
|
||||
{
|
||||
BitStore store(size);
|
||||
|
||||
// check serialization for all bits, only one bit is set
|
||||
for(int index = 0; index < size; index++)
|
||||
{
|
||||
store.setBit(index, true);
|
||||
|
||||
checkSerialization(&store);
|
||||
store.clearBits();
|
||||
}
|
||||
}
|
||||
|
||||
// check serialization for BitStore with random values
|
||||
BitStore store(TESTBITSTORE_MAX_BITSTORE_SIZE);
|
||||
Random rand;
|
||||
|
||||
for(int count = 0; count < TESTBITSTORE_RANDOM_VALUES_COUNT; count++)
|
||||
{
|
||||
int randIndex = rand.getNextInRange(0, TESTBITSTORE_MAX_BITSTORE_SIZE - 1);
|
||||
store.setBit(randIndex, true);
|
||||
}
|
||||
|
||||
checkSerialization(&store);
|
||||
}
|
||||
29
common/tests/TestEntryIdTk.cpp
Normal file
29
common/tests/TestEntryIdTk.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <common/toolkit/EntryIdTk.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(EntryIdTk, isValidHexToken)
|
||||
{
|
||||
using EntryIdTk::isValidHexToken;
|
||||
|
||||
EXPECT_TRUE(isValidHexToken("0"));
|
||||
EXPECT_FALSE(isValidHexToken(""));
|
||||
EXPECT_TRUE(isValidHexToken(std::string(8, '0')));
|
||||
EXPECT_FALSE(isValidHexToken(std::string(9, '0')));
|
||||
EXPECT_TRUE(isValidHexToken("123ADB"));
|
||||
EXPECT_FALSE(isValidHexToken("123ADBS"));
|
||||
}
|
||||
|
||||
TEST(EntryIdTk, isValidEntryIdFormat)
|
||||
{
|
||||
using EntryIdTk::isValidEntryIdFormat;
|
||||
|
||||
EXPECT_TRUE(isValidEntryIdFormat("0-59F03330-1"));
|
||||
|
||||
EXPECT_TRUE(isValidEntryIdFormat("0-0-0"));
|
||||
EXPECT_FALSE(isValidEntryIdFormat("0-0-0-0"));
|
||||
EXPECT_FALSE(isValidEntryIdFormat("0-0"));
|
||||
EXPECT_FALSE(isValidEntryIdFormat("-0"));
|
||||
EXPECT_FALSE(isValidEntryIdFormat("0-"));
|
||||
EXPECT_FALSE(isValidEntryIdFormat("--"));
|
||||
}
|
||||
99
common/tests/TestIPv4Network.cpp
Normal file
99
common/tests/TestIPv4Network.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <common/net/sock/NetworkInterfaceCard.cpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
struct TestIPv4NetworkParseResult
|
||||
{
|
||||
const char* cidr;
|
||||
bool valid;
|
||||
struct in_addr address;
|
||||
uint8_t prefix;
|
||||
struct in_addr netmask;
|
||||
};
|
||||
|
||||
struct TestIPv4NetworkParseResult const __TESTIPV4NETWORK_PARSE_RESULTS[] =
|
||||
{
|
||||
{"0.0.0.0/0", true, in_addr_ctor(0), 0, in_addr_ctor(0)},
|
||||
{"10.0.0.0/8", true, in_addr_ctor(0x0a), 8, in_addr_ctor(0x0ff)},
|
||||
{"10.11.0.0/16", true, in_addr_ctor(0x0b0a), 16, in_addr_ctor(0x0ffff)},
|
||||
{"10.11.12.0/24", true, in_addr_ctor(0x0c0b0a), 24, in_addr_ctor(0x0ffffff)},
|
||||
{"10.11.12.1/32", true, in_addr_ctor(0x010c0b0a), 32, in_addr_ctor(0x0ffffffff)},
|
||||
{"10.11.12.1/", false},
|
||||
{"10.11.12.1/33", false},
|
||||
{"10.11.12.1/-1", false},
|
||||
{"foo.com/16", false},
|
||||
{"", false},
|
||||
{"/", false},
|
||||
{"10.11.12.1/16", true, in_addr_ctor(0x0b0a), 16, in_addr_ctor(0x0ffff)},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TestIPv4Network : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(TestIPv4Network, parseCidr)
|
||||
{
|
||||
for (int i = 0; __TESTIPV4NETWORK_PARSE_RESULTS[i].cidr != NULL; ++i)
|
||||
{
|
||||
auto& r = __TESTIPV4NETWORK_PARSE_RESULTS[i];
|
||||
IPv4Network n;
|
||||
//std::cerr << "parse " << r.cidr << std::endl;
|
||||
bool v = IPv4Network::parse(r.cidr, n);
|
||||
EXPECT_EQ(r.valid, v) << r.cidr << " should be " << (r.valid? "valid" : "invalid");
|
||||
if (v)
|
||||
{
|
||||
EXPECT_EQ(r.address, n.address) << r.cidr << " address should be " << std::hex << r.address.s_addr;
|
||||
EXPECT_EQ(r.netmask, n.netmask) << r.cidr << " netmask should be " << std::hex << r.netmask.s_addr;
|
||||
EXPECT_EQ(r.prefix, n.prefix) << r.cidr << " prefix should be " << (int) r.prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestIPv4Network, matches24)
|
||||
{
|
||||
IPv4Network net;
|
||||
struct in_addr ina;
|
||||
EXPECT_EQ(true, IPv4Network::parse("192.168.1.0/24", net));
|
||||
for (int i = 1; i <= 255; ++i)
|
||||
{
|
||||
std::string a = std::string("192.168.1.") + std::to_string(i);
|
||||
EXPECT_EQ(1, inet_pton(AF_INET, a.c_str(), &ina));
|
||||
EXPECT_EQ(true, net.matches(ina));
|
||||
}
|
||||
for (int i = 1; i <= 255; ++i)
|
||||
{
|
||||
std::string a = std::string("192.168.2.") + std::to_string(i);
|
||||
EXPECT_EQ(1, inet_pton(AF_INET, a.c_str(), &ina));
|
||||
EXPECT_EQ(false, net.matches(ina));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestIPv4Network, matches32)
|
||||
{
|
||||
IPv4Network net;
|
||||
struct in_addr ina;
|
||||
EXPECT_EQ(true, IPv4Network::parse("192.168.1.128/32", net));
|
||||
for (int i = 1; i <= 255; ++i)
|
||||
{
|
||||
std::string a = std::string("192.168.1.") + std::to_string(i);
|
||||
EXPECT_EQ(1, inet_pton(AF_INET, a.c_str(), &ina));
|
||||
EXPECT_EQ(i == 128, net.matches(ina));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestIPv4Network, matches0)
|
||||
{
|
||||
IPv4Network net;
|
||||
struct in_addr ina;
|
||||
EXPECT_EQ(true, IPv4Network::parse("0.0.0.0/0", net));
|
||||
for (int i = 1; i <= 255; ++i)
|
||||
{
|
||||
std::string a = std::string("192.168.1.") + std::to_string(i);
|
||||
EXPECT_EQ(1, inet_pton(AF_INET, a.c_str(), &ina));
|
||||
EXPECT_EQ(true, net.matches(ina));
|
||||
}
|
||||
}
|
||||
23
common/tests/TestListTk.cpp
Normal file
23
common/tests/TestListTk.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <common/toolkit/ListTk.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(ListTk, advance)
|
||||
{
|
||||
IntList list;
|
||||
IntListIter iter;
|
||||
|
||||
for (int i=0; i<10;i++)
|
||||
{
|
||||
list.push_back(i);
|
||||
}
|
||||
|
||||
iter = list.begin();
|
||||
ListTk::advance(list, iter, 5);
|
||||
|
||||
ASSERT_EQ(*iter, 5);
|
||||
|
||||
ListTk::advance(list, iter, 44);
|
||||
|
||||
ASSERT_EQ(iter, list.end());
|
||||
}
|
||||
99
common/tests/TestLockFD.cpp
Normal file
99
common/tests/TestLockFD.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <common/toolkit/LockFD.h>
|
||||
#include <common/toolkit/StorageTk.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TestLockFD : public ::testing::Test {
|
||||
protected:
|
||||
std::string tmpDir;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
tmpDir = "tmpXXXXXX";
|
||||
tmpDir += '\0';
|
||||
ASSERT_NE(mkdtemp(&tmpDir[0]), nullptr);
|
||||
tmpDir.resize(tmpDir.size() - 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
StorageTk::removeDirRecursive(tmpDir);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestLockFD, testInitialLock)
|
||||
{
|
||||
const auto path = tmpDir + "/initial";
|
||||
|
||||
auto lock = LockFD::lock(path, false);
|
||||
ASSERT_TRUE(lock);
|
||||
|
||||
FDHandle fd(open(path.c_str(), O_RDONLY));
|
||||
ASSERT_TRUE(fd.valid());
|
||||
|
||||
ASSERT_EQ(flock(*fd, LOCK_EX | LOCK_NB), -1);
|
||||
ASSERT_EQ(errno, EWOULDBLOCK);
|
||||
}
|
||||
|
||||
TEST_F(TestLockFD, testLockTwice)
|
||||
{
|
||||
const auto path = tmpDir + "/twice";
|
||||
|
||||
auto lock1 = LockFD::lock(path, false);
|
||||
ASSERT_TRUE(lock1);
|
||||
|
||||
auto lock2 = LockFD::lock(path, false);
|
||||
ASSERT_FALSE(lock2);
|
||||
ASSERT_EQ(lock2.error().value(), EWOULDBLOCK);
|
||||
}
|
||||
|
||||
TEST_F(TestLockFD, testDoesUnlink)
|
||||
{
|
||||
const auto path = tmpDir + "/unlinks";
|
||||
|
||||
auto lock = LockFD::lock(path, false);
|
||||
ASSERT_TRUE(lock);
|
||||
lock = {};
|
||||
|
||||
ASSERT_EQ(access(path.c_str(), R_OK), -1);
|
||||
}
|
||||
|
||||
TEST_F(TestLockFD, testUpdate)
|
||||
{
|
||||
const auto path = tmpDir + "/update";
|
||||
|
||||
{
|
||||
auto lock = LockFD::lock(path, false).release_value();
|
||||
ASSERT_TRUE(lock.update("test"));
|
||||
ASSERT_TRUE(lock.updateWithPID());
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockFD::lock(path, true).release_value();
|
||||
|
||||
{
|
||||
ASSERT_FALSE(lock.update("test"));
|
||||
std::ifstream file(path);
|
||||
char buf[10];
|
||||
file.read(buf, 5);
|
||||
ASSERT_TRUE(file.eof());
|
||||
ASSERT_EQ(file.gcount(), 4);
|
||||
ASSERT_EQ(memcmp(buf, "test", 4), 0);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_FALSE(lock.updateWithPID());
|
||||
std::ifstream file(path);
|
||||
char buf[100];
|
||||
const auto expected = std::to_string(getpid()) + '\n';
|
||||
file.read(buf, 100);
|
||||
ASSERT_TRUE(file.eof());
|
||||
ASSERT_EQ(size_t(file.gcount()), expected.size());
|
||||
ASSERT_EQ(memcmp(buf, &expected[0], expected.size()), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
common/tests/TestNIC.cpp
Normal file
17
common/tests/TestNIC.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <common/net/sock/NetworkInterfaceCard.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(NIC, nic)
|
||||
{
|
||||
NicAddressList list;
|
||||
StringList allowedInterfaces;
|
||||
|
||||
ASSERT_TRUE(NetworkInterfaceCard::findAll(&allowedInterfaces, true, &list));
|
||||
|
||||
ASSERT_FALSE(list.empty());
|
||||
|
||||
NicAddress nicAddr;
|
||||
|
||||
ASSERT_TRUE(NetworkInterfaceCard::findByName(list.begin()->name, &nicAddr));
|
||||
}
|
||||
88
common/tests/TestNetFilter.cpp
Normal file
88
common/tests/TestNetFilter.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include <common/toolkit/NetFilter.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TestNetFilter : public ::testing::Test {
|
||||
protected:
|
||||
std::string fileName;
|
||||
|
||||
void createFile(const char* content)
|
||||
{
|
||||
fileName = "/tmp/XXXXXX";
|
||||
int fd = mkstemp(&fileName[0]);
|
||||
ASSERT_GE(fd, 0);
|
||||
ASSERT_EQ(write(fd, content, strlen(content)), ssize_t(strlen(content)));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
unlink(fileName.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestNetFilter, noFile)
|
||||
{
|
||||
NetFilter filter("");
|
||||
|
||||
ASSERT_EQ(filter.getNumFilterEntries(), 0u);
|
||||
|
||||
// always allow loopback
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(INADDR_LOOPBACK)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(INADDR_LOOPBACK)));
|
||||
|
||||
// can't check for all ips, try a random one
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(0xd5c1a899)));
|
||||
EXPECT_FALSE(filter.isContained(htonl(0xd5c1a899)));
|
||||
}
|
||||
|
||||
TEST_F(TestNetFilter, netmask0)
|
||||
{
|
||||
createFile("10.0.0.0/0");
|
||||
|
||||
NetFilter filter(fileName);
|
||||
|
||||
ASSERT_EQ(filter.getNumFilterEntries(), 1u);
|
||||
|
||||
// always allow loopback
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(INADDR_LOOPBACK)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(INADDR_LOOPBACK)));
|
||||
|
||||
// 10.0.0.x should definitely be allowed
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(0x0a010203)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(0x0a010203)));
|
||||
|
||||
// netfilter /0 says everything else is allowed too
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(0xd5c1a899)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(0xd5c1a899)));
|
||||
}
|
||||
|
||||
TEST_F(TestNetFilter, netmaskExclusive)
|
||||
{
|
||||
createFile("10.0.0.0/24\n10.1.0.0/24");
|
||||
|
||||
NetFilter filter(fileName);
|
||||
|
||||
ASSERT_EQ(filter.getNumFilterEntries(), 2u);
|
||||
|
||||
// always allow loopback
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(INADDR_LOOPBACK)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(INADDR_LOOPBACK)));
|
||||
|
||||
// 10.0.0.x should definitely be allowed
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(0x0a000003)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(0x0a000003)));
|
||||
// 10.0.1.x should not be allowed
|
||||
EXPECT_FALSE(filter.isAllowed(htonl(0x0a000103)));
|
||||
EXPECT_FALSE(filter.isContained(htonl(0x0a000103)));
|
||||
|
||||
// same thing for 10.1.0.x
|
||||
EXPECT_TRUE(filter.isAllowed(htonl(0x0a010003)));
|
||||
EXPECT_TRUE(filter.isContained(htonl(0x0a010003)));
|
||||
EXPECT_FALSE(filter.isAllowed(htonl(0x0a010103)));
|
||||
EXPECT_FALSE(filter.isContained(htonl(0x0a010103)));
|
||||
|
||||
// other addresses are forbidden
|
||||
EXPECT_FALSE(filter.isAllowed(htonl(0xd5c1a899)));
|
||||
EXPECT_FALSE(filter.isContained(htonl(0xd5c1a899)));
|
||||
}
|
||||
23
common/tests/TestPath.cpp
Normal file
23
common/tests/TestPath.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <common/storage/Path.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Path, path)
|
||||
{
|
||||
std::vector<std::string> origPathElems = {
|
||||
"xyz",
|
||||
"subdir",
|
||||
"file",
|
||||
};
|
||||
|
||||
std::string pathStr;
|
||||
for (auto iter = origPathElems.begin(); iter != origPathElems.end(); iter++)
|
||||
pathStr += "/" + *iter;
|
||||
|
||||
Path path(pathStr);
|
||||
|
||||
ASSERT_EQ(path.size(), origPathElems.size());
|
||||
|
||||
for (size_t i = 0; i < path.size(); i++)
|
||||
ASSERT_EQ(path[i], origPathElems[i]);
|
||||
}
|
||||
65
common/tests/TestPreallocatedFile.cpp
Normal file
65
common/tests/TestPreallocatedFile.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <common/toolkit/PreallocatedFile.h>
|
||||
#include <common/toolkit/StorageTk.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TestPreallocatedFile : public ::testing::Test {
|
||||
protected:
|
||||
std::string tmpDir;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
tmpDir = "tmpXXXXXX";
|
||||
tmpDir += '\0';
|
||||
ASSERT_NE(mkdtemp(&tmpDir[0]), nullptr);
|
||||
tmpDir.resize(tmpDir.size() - 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
StorageTk::removeDirRecursive(tmpDir);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestPreallocatedFile, allocation)
|
||||
{
|
||||
const auto path = tmpDir + "/file";
|
||||
|
||||
PreallocatedFile<char, 1024*1024> file(path, 0600);
|
||||
|
||||
struct stat st;
|
||||
ASSERT_EQ(::stat(path.c_str(), &st), 0);
|
||||
ASSERT_EQ(st.st_size, 1024*1024+1);
|
||||
ASSERT_GE(st.st_blocks * 512, 1024*1024+1);
|
||||
}
|
||||
|
||||
TEST_F(TestPreallocatedFile, allocationFailure)
|
||||
{
|
||||
// This should throw because filesystems can't provide 2**63 writable bytes in a single file as
|
||||
// of writing this test and probably won't for a long time after.
|
||||
ASSERT_THROW(([this] {
|
||||
PreallocatedFile<char, std::numeric_limits<off_t>::max()> file(tmpDir + "/file", 0600);
|
||||
})(),
|
||||
std::system_error);
|
||||
}
|
||||
|
||||
TEST_F(TestPreallocatedFile, readWrite)
|
||||
{
|
||||
const auto goodPath = tmpDir + "/good";
|
||||
|
||||
PreallocatedFile<uint64_t> good(goodPath, 0600);
|
||||
PreallocatedFile<uint64_t, 1> bad(tmpDir + "/bad", 0600);
|
||||
|
||||
good.write(0x0102030405060708ULL);
|
||||
ASSERT_THROW(bad.write(0), std::runtime_error);
|
||||
|
||||
ASSERT_EQ(*good.read(), 0x0102030405060708ULL);
|
||||
ASSERT_EQ(bad.read(), boost::none);
|
||||
|
||||
ASSERT_EQ(::truncate(goodPath.c_str(), 0), 0);
|
||||
ASSERT_THROW(good.read(), std::system_error);
|
||||
}
|
||||
834
common/tests/TestRWLock.cpp
Normal file
834
common/tests/TestRWLock.cpp
Normal file
@@ -0,0 +1,834 @@
|
||||
#include <common/app/log/LogContext.h>
|
||||
#include <common/threading/RWLock.h>
|
||||
#include <common/toolkit/Random.h>
|
||||
#include <common/toolkit/StringTk.h>
|
||||
#include <common/toolkit/Time.h>
|
||||
|
||||
#include "TestRWLock.h"
|
||||
|
||||
// rwlock tests are disabled by default, probably due to long runtime.
|
||||
#define RWLOCK_TEST(id) TEST_F(TestRWLock, DISABLED_ ## id)
|
||||
|
||||
|
||||
/*
|
||||
* sorts all threads by the lock timestamp, make it easier to verify the execution order
|
||||
*/
|
||||
void TestRWLock::sortThreadsInLockTimestamp(TestLockThread* threads,
|
||||
Time* startTime)
|
||||
{
|
||||
bool changesDone = false;
|
||||
|
||||
do
|
||||
{
|
||||
changesDone = false;
|
||||
|
||||
for (int id = 0; id < (TestRWLock_THREAD_COUNT -1); id++)
|
||||
{
|
||||
int elapsedTimeID = threads[id].getLockTimestamp().
|
||||
elapsedSinceMS(startTime);
|
||||
int elapsedTimeNextID = threads[id + 1].getLockTimestamp().
|
||||
elapsedSinceMS(startTime);
|
||||
|
||||
if (elapsedTimeID > elapsedTimeNextID)
|
||||
{
|
||||
TestLockThread tmpTestLockThread;
|
||||
tmpTestLockThread.copy(&threads[id]);
|
||||
threads[id].copy(&threads[id + 1]);
|
||||
threads[id + 1 ].copy(&tmpTestLockThread);
|
||||
changesDone = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (changesDone);
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze the run time for random thread execution, if the run time was long enough
|
||||
*/
|
||||
void TestRWLock::checkRandomRuntime(TestLockThread* threads, int runtimeMS)
|
||||
{
|
||||
int minimalRuntimeMS = 0;
|
||||
int longestSleepMS = 0;
|
||||
|
||||
for (int id = 0; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
// ignore threads which didn't get a lock
|
||||
if (!threads[id].getLockSuccess())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (threads[id].getDoReadLock())
|
||||
{ // reader thread, find the longest sleep time
|
||||
for (int nextId = id + 1; nextId < TestRWLock_THREAD_COUNT; nextId++)
|
||||
{
|
||||
// check all reader threads which was executed at the same time
|
||||
if(threads[nextId].getDoReadLock())
|
||||
{ // next thread was a reader, find the longest sleep time
|
||||
if (threads[nextId].getLockSuccess() &&
|
||||
(longestSleepMS < threads[nextId].getSleepTimeMS()))
|
||||
{
|
||||
longestSleepMS = threads[nextId].getSleepTimeMS();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // next thread was a writer, stop searching of longest sleep time
|
||||
id = nextId - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
minimalRuntimeMS = minimalRuntimeMS + longestSleepMS;
|
||||
}
|
||||
else
|
||||
{ // writer thread, add the the sleep time
|
||||
minimalRuntimeMS = minimalRuntimeMS + threads[id].getSleepTimeMS();
|
||||
}
|
||||
}
|
||||
|
||||
// check if the sleep time is bigger then the runtime
|
||||
if (minimalRuntimeMS > runtimeMS)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze the execution order for random thread execution
|
||||
*/
|
||||
void TestRWLock::checkRandomExecutionOrder(TestLockThread* threads)
|
||||
{
|
||||
for (int id = 1; id < (TestRWLock_THREAD_COUNT); id++)
|
||||
{
|
||||
// ignore threads which didn't get a lock
|
||||
if(!threads[id].getLockSuccess())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the unlock was successful
|
||||
if(!threads[id].getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "Test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
// check the execution order
|
||||
if(threads[id].getDoReadLock())
|
||||
{
|
||||
checkRandomExecutionOrderReader(threads, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkRandomExecutionOrderWriter(threads, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze the execution order for random thread execution for a reader thread
|
||||
*/
|
||||
void TestRWLock::checkRandomExecutionOrderReader(TestLockThread* threads, int threadID)
|
||||
{
|
||||
for (int beforeId = threadID - 1; beforeId >= 0; beforeId--)
|
||||
{
|
||||
if(threads[beforeId].getLockSuccess())
|
||||
{
|
||||
Time unlockTimeBefore = threads[beforeId].getUnlockTimestamp();
|
||||
Time lockTime = threads[threadID].getLockTimestamp();
|
||||
|
||||
// check if the thread before was a writer and check if the thread before has unlocked
|
||||
// the rwlock before this reader thread locks the rwlock
|
||||
// if the thread before was a reader it is OK to get the lock without a unlock
|
||||
if((!threads[beforeId].getDoReadLock()) && (unlockTimeBefore > lockTime))
|
||||
{
|
||||
std::cerr << "execution order failed, time diff in micro sec: " << StringTk::uintToStr(
|
||||
unlockTimeBefore.elapsedSinceMicro(&lockTime)) << std::endl;
|
||||
FAIL() << "Test thread got the lock, but it wasn't possible to get the lock.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze the execution order for random thread execution for a writer thread
|
||||
*/
|
||||
void TestRWLock::checkRandomExecutionOrderWriter(TestLockThread* threads, int threadID)
|
||||
{
|
||||
for (int beforeId = threadID - 1; beforeId >= 0; beforeId--)
|
||||
{
|
||||
if(threads[beforeId].getLockSuccess())
|
||||
{
|
||||
Time unlockTimeBefore = threads[beforeId].getUnlockTimestamp();
|
||||
Time lockTime = threads[threadID].getLockTimestamp();
|
||||
|
||||
// check if the thread before has unlocked the rwlock before this writer thread locks
|
||||
// the rwlock
|
||||
if(unlockTimeBefore > lockTime)
|
||||
{
|
||||
std::cerr << "execution order failed, time diff in micro sec: " << StringTk::uintToStr(
|
||||
unlockTimeBefore.elapsedSinceMicro(&lockTime)) << std::endl;
|
||||
FAIL() << "Test thread got the lock, but it wasn't possible to get the lock.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a reader thread on a read lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(readerOnReader)
|
||||
{
|
||||
// creates a read lock
|
||||
RWLock lock;
|
||||
lock.readLock();
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a read lock
|
||||
TestLockThread thread(&lock, true, false);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (!thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't get the lock, but it was possible to get the lock.";
|
||||
}
|
||||
|
||||
if (!thread.getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
if (TestRWLock_SLEEP_TIME_MS > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a reader thread on a write lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(readerOnWriter)
|
||||
{
|
||||
// creates a write lock
|
||||
RWLock lock;
|
||||
lock.writeLock();
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a read lock
|
||||
TestLockThread thread(&lock, true, false);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (!thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't get the lock, but it was possible to get the lock.";
|
||||
}
|
||||
|
||||
if (!thread.getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS * 2) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a writer thread on a read lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(writerOnReader)
|
||||
{
|
||||
// creates a read lock
|
||||
RWLock lock;
|
||||
lock.readLock();
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a write lock
|
||||
TestLockThread thread(&lock, false, false);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (!thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't get the lock, but it was possible to get the lock.";
|
||||
}
|
||||
|
||||
if (!thread.getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS * 2) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a writer thread on a write lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(writerOnWriter)
|
||||
{
|
||||
// creates a write lock
|
||||
RWLock lock;
|
||||
lock.writeLock();
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a write lock
|
||||
TestLockThread thread(&lock, false, false);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (!thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't get the lock, but it was possible to get the lock.";
|
||||
}
|
||||
|
||||
if (!thread.getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS * 2) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests reader threads and writer thread on a read lock, checks massive amount of lock operations
|
||||
*/
|
||||
RWLOCK_TEST(randomOnReader)
|
||||
{
|
||||
RWLock lock;
|
||||
Random randomizer;
|
||||
TestLockThread threadList[TestRWLock_THREAD_COUNT];
|
||||
|
||||
int id = 0;
|
||||
|
||||
threadList[0].init(&lock, true, false, TestRWLock_SLEEP_TIME_MS, 1);
|
||||
|
||||
// create all threads for the test
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
bool tmpDoReadLock;
|
||||
|
||||
// random initialization: is reader or writer
|
||||
tmpDoReadLock = randomizer.getNextInRange(0, 1) == 1;
|
||||
|
||||
// random initialization: sleep time
|
||||
int tmpSleepTimeMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MIN_MS,
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MAX_MS);
|
||||
|
||||
// random initialization: start delay time
|
||||
int tmpLockDelayMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MIN_MS,
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MAX_MS);
|
||||
|
||||
threadList[id].init(&lock, tmpDoReadLock, false, tmpSleepTimeMS, tmpLockDelayMS);
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// start all threads
|
||||
threadList[0].start();
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
threadList[id].start();
|
||||
}
|
||||
|
||||
bool notTimedOut = true;
|
||||
Time startTimeout;
|
||||
|
||||
// collect all threads and check timeout
|
||||
for (id = 0; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
int nextTimeout = TestRWLock_MULTI_TIMEOUT_MS - startTimeout.elapsedMS();
|
||||
if (nextTimeout < 500)
|
||||
{
|
||||
nextTimeout = 500;
|
||||
}
|
||||
|
||||
if (!threadList[id].timedjoin(nextTimeout))
|
||||
{
|
||||
notTimedOut = false;
|
||||
}
|
||||
}
|
||||
|
||||
int runtimeMS = startTime.elapsedMS();
|
||||
|
||||
// check the constraints
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
sortThreadsInLockTimestamp(threadList, &startTime);
|
||||
checkRandomExecutionOrder(threadList);
|
||||
checkRandomRuntime(threadList, runtimeMS);
|
||||
}
|
||||
|
||||
/*
|
||||
* tests reader threads and writer thread on a write lock, checks massive amount of lock operations
|
||||
*/
|
||||
RWLOCK_TEST(randomOnWriter)
|
||||
{
|
||||
RWLock lock;
|
||||
Random randomizer;
|
||||
TestLockThread threadList[TestRWLock_THREAD_COUNT];
|
||||
|
||||
int id = 0;
|
||||
|
||||
threadList[0].init(&lock, false, false, 5000, 1);
|
||||
|
||||
// create all threads for the test
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
bool tmpDoReadLock;
|
||||
|
||||
// random initialization: is reader or writer
|
||||
tmpDoReadLock = randomizer.getNextInRange(0, 1) == 1;
|
||||
|
||||
// random initialization: sleep time
|
||||
int tmpSleepTimeMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MIN_MS,
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MAX_MS);
|
||||
|
||||
// random initialization: start delay time
|
||||
int tmpLockDelayMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MIN_MS,
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MAX_MS);
|
||||
|
||||
threadList[id].init(&lock, tmpDoReadLock, false, tmpSleepTimeMS, tmpLockDelayMS);
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// start all threads
|
||||
threadList[0].start();
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
threadList[id].start();
|
||||
}
|
||||
|
||||
bool notTimedOut = true;
|
||||
Time startTimeout;
|
||||
|
||||
// collect all threads and check timeout
|
||||
for (id = 0; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
int nextTimeout = TestRWLock_MULTI_TIMEOUT_MS - startTimeout.elapsedMS();
|
||||
if (nextTimeout < 500)
|
||||
{
|
||||
nextTimeout = 500;
|
||||
}
|
||||
|
||||
if (!threadList[id].timedjoin(nextTimeout))
|
||||
{
|
||||
notTimedOut = false;
|
||||
}
|
||||
}
|
||||
|
||||
int runtimeMS = startTime.elapsedMS();
|
||||
|
||||
// check the constraints
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
sortThreadsInLockTimestamp(threadList, &startTime);
|
||||
checkRandomExecutionOrder(threadList);
|
||||
checkRandomRuntime(threadList, runtimeMS);
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a tryReadLock on a read lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(tryReadOnReader)
|
||||
{
|
||||
// creates a read lock with try method
|
||||
RWLock lock;
|
||||
|
||||
bool success = lock.tryReadLock();
|
||||
if (!success)
|
||||
{
|
||||
FAIL() << "Couldn't get initial lock.";
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a read lock with try method
|
||||
TestLockThread thread(&lock, true, true);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (!thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't get the lock, but it was possible to get the lock.";
|
||||
}
|
||||
|
||||
if (!thread.getUnlockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread didn't unlock the lock.";
|
||||
}
|
||||
|
||||
if (TestRWLock_SLEEP_TIME_MS > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a tryReadLock on a write lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(tryReadOnWriter)
|
||||
{
|
||||
// creates a write lock with try method
|
||||
RWLock lock;
|
||||
|
||||
bool success = lock.tryWriteLock();
|
||||
if (!success)
|
||||
{
|
||||
FAIL() << "Couldn't get initial lock.";
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a read lock with try method
|
||||
TestLockThread thread(&lock, true, true);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread got the lock, but it wasn't possible to get the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a tryWriteLock on a read lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(tryWriteOnReader)
|
||||
{
|
||||
// creates a read lock with try method
|
||||
RWLock lock;
|
||||
|
||||
bool success = lock.tryReadLock();
|
||||
if (!success)
|
||||
{
|
||||
FAIL() << "Couldn't get initial lock.";
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a write lock with try method
|
||||
TestLockThread thread(&lock, false, true);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread got the lock, but it wasn't possible to get the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests a tryWriteLock on a write lock, checks the basic functions of a rwlock
|
||||
*/
|
||||
RWLOCK_TEST(tryWriteOnWriter)
|
||||
{
|
||||
// creates a write lock with try method
|
||||
RWLock lock;
|
||||
|
||||
bool success = lock.tryWriteLock();
|
||||
if (!success)
|
||||
{
|
||||
FAIL() << "Couldn't get initial lock.";
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// creates a write lock with try method
|
||||
TestLockThread thread(&lock, false, true);
|
||||
thread.start();
|
||||
|
||||
// wait a few second before unlock the lock
|
||||
PThread::sleepMS(TestRWLock_SLEEP_TIME_MS);
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// wait for timeout
|
||||
bool notTimedOut = thread.timedjoin(2 * TestRWLock_SINGLE_TIMEOUT_MS);
|
||||
int runtime = startTime.elapsedMS();
|
||||
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
if (thread.getLockSuccess())
|
||||
{
|
||||
FAIL() << "The test thread got the lock, but it wasn't possible to get the lock.";
|
||||
}
|
||||
|
||||
if ((TestRWLock_SLEEP_TIME_MS) > runtime)
|
||||
{
|
||||
FAIL() << "Runtime is to short. A lock didn't work.";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tests tryReadLock and tryWriteLock on a read lock, checks massive amount of lock operations
|
||||
*/
|
||||
RWLOCK_TEST(randomTryOnReader)
|
||||
{
|
||||
RWLock lock;
|
||||
Random randomizer;
|
||||
TestLockThread threadList[TestRWLock_THREAD_COUNT];
|
||||
|
||||
int id = 0;
|
||||
|
||||
threadList[0].init(&lock, true, true, 5000, 1);
|
||||
|
||||
// create all threads for the test
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
bool tmpDoReadLock;
|
||||
|
||||
// random initialization: is reader or writer
|
||||
tmpDoReadLock = randomizer.getNextInRange(0, 1) == 1;
|
||||
|
||||
// random initialization: sleep time
|
||||
int tmpSleepTimeMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MIN_MS,
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MAX_MS);
|
||||
|
||||
// random initialization: start delay time
|
||||
int tmpLockDelayMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MIN_MS,
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MAX_MS);
|
||||
|
||||
threadList[id].init(&lock, tmpDoReadLock, true, tmpSleepTimeMS, tmpLockDelayMS);
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// start all threads
|
||||
threadList[0].start();
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
threadList[id].start();
|
||||
}
|
||||
|
||||
bool notTimedOut = true;
|
||||
Time startTimeout;
|
||||
|
||||
// collect all threads and check timeout
|
||||
for (id = 0; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
int nextTimeout = TestRWLock_MULTI_TIMEOUT_MS - startTimeout.elapsedMS();
|
||||
if (nextTimeout < 500)
|
||||
{
|
||||
nextTimeout = 500;
|
||||
}
|
||||
|
||||
if (!threadList[id].timedjoin(nextTimeout))
|
||||
{
|
||||
notTimedOut = false;
|
||||
}
|
||||
}
|
||||
|
||||
int runtimeMS = startTime.elapsedMS();
|
||||
|
||||
// check the constraints
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
sortThreadsInLockTimestamp(threadList, &startTime);
|
||||
checkRandomExecutionOrder(threadList);
|
||||
checkRandomRuntime(threadList, runtimeMS);
|
||||
}
|
||||
|
||||
/*
|
||||
* tests tryReadLock and tryWriteLock on a write lock, checks massive amount of lock operations
|
||||
*/
|
||||
RWLOCK_TEST(randomTryOnWriter)
|
||||
{
|
||||
RWLock lock;
|
||||
Random randomizer;
|
||||
TestLockThread threadList[TestRWLock_THREAD_COUNT];
|
||||
|
||||
int id = 0;
|
||||
|
||||
threadList[0].init(&lock, false, true, 5000, 1);
|
||||
|
||||
// create all threads for the test
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
bool tmpDoReadLock;
|
||||
|
||||
// random initialization: is reader or writer
|
||||
tmpDoReadLock = randomizer.getNextInRange(0, 1) == 1;
|
||||
|
||||
// random initialization: sleep time
|
||||
int tmpSleepTimeMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MIN_MS,
|
||||
TestRWLock_RANDOM_SLEEP_TIME_MAX_MS);
|
||||
|
||||
// random initialization: start delay time
|
||||
int tmpLockDelayMS = randomizer.getNextInRange(
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MIN_MS,
|
||||
TestRWLock_RANDOM_LOCK_DELAY_MAX_MS);
|
||||
|
||||
threadList[id].init(&lock, tmpDoReadLock, true, tmpSleepTimeMS, tmpLockDelayMS);
|
||||
}
|
||||
|
||||
Time startTime;
|
||||
|
||||
// start all threads
|
||||
threadList[0].start();
|
||||
for (id = 1; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
threadList[id].start();
|
||||
}
|
||||
|
||||
bool notTimedOut = true;
|
||||
Time startTimeout;
|
||||
|
||||
// collect all threads and check timeout
|
||||
for (id = 0; id < TestRWLock_THREAD_COUNT; id++)
|
||||
{
|
||||
int nextTimeout = TestRWLock_MULTI_TIMEOUT_MS - startTimeout.elapsedMS();
|
||||
if (nextTimeout < 500)
|
||||
{
|
||||
nextTimeout = 500;
|
||||
}
|
||||
|
||||
if (!threadList[id].timedjoin(nextTimeout))
|
||||
{
|
||||
notTimedOut = false;
|
||||
}
|
||||
}
|
||||
|
||||
int runtimeMS = startTime.elapsedMS();
|
||||
|
||||
// check the constraints
|
||||
if (!notTimedOut)
|
||||
{
|
||||
FAIL() << "Test ran into a timeout. Maybe a dead-lock";
|
||||
}
|
||||
|
||||
sortThreadsInLockTimestamp(threadList, &startTime);
|
||||
checkRandomExecutionOrder(threadList);
|
||||
checkRandomRuntime(threadList, runtimeMS);
|
||||
}
|
||||
230
common/tests/TestRWLock.h
Normal file
230
common/tests/TestRWLock.h
Normal file
@@ -0,0 +1,230 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <common/threading/Condition.h>
|
||||
#include <common/threading/RWLock.h>
|
||||
#include <common/threading/PThread.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
// configuration for the tests
|
||||
#define TestRWLock_THREAD_COUNT 50
|
||||
#define TestRWLock_LOCK_DELAY_MS 1000
|
||||
#define TestRWLock_SLEEP_TIME_S 3
|
||||
#define TestRWLock_SLEEP_TIME_MS (TestRWLock_SLEEP_TIME_S * 1000)
|
||||
#define TestRWLock_RANDOM_SLEEP_TIME_MIN_MS 1000
|
||||
#define TestRWLock_RANDOM_SLEEP_TIME_MAX_MS 4000
|
||||
#define TestRWLock_RANDOM_LOCK_DELAY_MIN_MS 2000
|
||||
#define TestRWLock_RANDOM_LOCK_DELAY_MAX_MS 8000
|
||||
#define TestRWLock_SINGLE_TIMEOUT_MS 15000
|
||||
#define TestRWLock_MULTI_TIMEOUT_MS (TestRWLock_SINGLE_TIMEOUT_MS * TestRWLock_THREAD_COUNT)
|
||||
|
||||
|
||||
class TestRWLock: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Thread for testing the concurrent access to a shared resource which is secured by
|
||||
* an rwlock
|
||||
*/
|
||||
class TestLockThread: public PThread
|
||||
{
|
||||
public:
|
||||
TestLockThread() : PThread("RWLockTester")
|
||||
{
|
||||
this->lock = NULL;
|
||||
|
||||
this->sleepTimeMS = TestRWLock_SLEEP_TIME_MS;
|
||||
this->lockDelayMS = TestRWLock_LOCK_DELAY_MS;
|
||||
|
||||
this->doReadLock = true;
|
||||
this->doTry = false;
|
||||
|
||||
this->lockSuccess = false;
|
||||
this->unlockSuccess = false;
|
||||
|
||||
this->lockTimestamp.setToNow();
|
||||
this->unlockTimestamp.setToNow();
|
||||
this->initTimestamp.setToNow();
|
||||
}
|
||||
|
||||
TestLockThread(RWLock* lock, bool doReadLock, bool doTry) : PThread("RWLockTester")
|
||||
{
|
||||
this->lock = lock;
|
||||
|
||||
this->sleepTimeMS = TestRWLock_SLEEP_TIME_MS;
|
||||
this->lockDelayMS = TestRWLock_LOCK_DELAY_MS;
|
||||
|
||||
this->doReadLock = doReadLock;
|
||||
this->doTry = doTry;
|
||||
|
||||
this->lockSuccess = false;
|
||||
this->unlockSuccess = false;
|
||||
|
||||
this->lockTimestamp.setToNow();
|
||||
this->unlockTimestamp.setToNow();
|
||||
this->initTimestamp.setToNow();
|
||||
}
|
||||
|
||||
TestLockThread(RWLock* lock, bool doReadLock, bool doTry, int sleepTimeMS,
|
||||
int lockDelayMS) : PThread("RWLockTester")
|
||||
{
|
||||
this->lock = lock;
|
||||
|
||||
this->sleepTimeMS = sleepTimeMS;
|
||||
this->lockDelayMS = lockDelayMS;
|
||||
|
||||
this->doReadLock = doReadLock;
|
||||
this->doTry = doTry;
|
||||
|
||||
this->lockSuccess = false;
|
||||
this->unlockSuccess = false;
|
||||
|
||||
this->lockTimestamp.setToNow();
|
||||
this->unlockTimestamp.setToNow();
|
||||
this->initTimestamp.setToNow();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
RWLock* lock; // the rwlock which all threads are use
|
||||
|
||||
int sleepTimeMS; // amount of to time to wait before start locking the rwlock
|
||||
int lockDelayMS; // the delay between the lock and the unlock
|
||||
|
||||
bool doReadLock; // true if this thread tries a read lock
|
||||
bool doTry; // true if a try*Lock will be used
|
||||
|
||||
bool lockSuccess; // true if the lock was successful
|
||||
bool unlockSuccess; // true if the unlock was successful
|
||||
|
||||
Time lockTimestamp; // the timestamp of the successful lock
|
||||
Time unlockTimestamp; // the timestamp of the successful unlock
|
||||
Time initTimestamp; // the timestamp at the end of the initialization
|
||||
|
||||
public:
|
||||
//public inliner
|
||||
|
||||
void init(RWLock* lock, bool doReadLock, bool doTry, int sleepTimeMS, int lockDelayMS)
|
||||
{
|
||||
this->lock = lock;
|
||||
|
||||
this->sleepTimeMS = sleepTimeMS;
|
||||
this->lockDelayMS = lockDelayMS;
|
||||
|
||||
this->doReadLock = doReadLock;
|
||||
this->doTry = doTry;
|
||||
|
||||
this->lockTimestamp.setToNow();
|
||||
this->unlockTimestamp.setToNow();
|
||||
this->initTimestamp.setToNow();
|
||||
}
|
||||
|
||||
void copy(TestLockThread* origin)
|
||||
{
|
||||
this->lock = origin->lock;
|
||||
|
||||
this->sleepTimeMS = origin->sleepTimeMS;
|
||||
this->lockDelayMS = origin->lockDelayMS;
|
||||
|
||||
this->doReadLock = origin->doReadLock;
|
||||
this->doTry = origin->doTry;
|
||||
|
||||
this->lockSuccess = origin->lockSuccess;
|
||||
this->unlockSuccess = origin->unlockSuccess;
|
||||
|
||||
this->lockTimestamp = Time(origin->lockTimestamp);
|
||||
this->unlockTimestamp = Time(origin->unlockTimestamp);
|
||||
this->initTimestamp = Time(origin->initTimestamp);
|
||||
}
|
||||
|
||||
bool getDoReadLock()
|
||||
{
|
||||
return this->doReadLock;
|
||||
}
|
||||
|
||||
bool getSleepTimeMS()
|
||||
{
|
||||
return this->sleepTimeMS;
|
||||
}
|
||||
|
||||
bool getLockSuccess()
|
||||
{
|
||||
return this->lockSuccess;
|
||||
}
|
||||
|
||||
bool getUnlockSuccess()
|
||||
{
|
||||
return this->unlockSuccess;
|
||||
}
|
||||
|
||||
Time getLockTimestamp()
|
||||
{
|
||||
return this->lockTimestamp;
|
||||
}
|
||||
|
||||
Time getUnlockTimestamp()
|
||||
{
|
||||
return this->unlockTimestamp;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// start delay for random start of the threads, this is needed for a random
|
||||
// execution order of the test threads, is necessary for a good test
|
||||
sleepMS(this->lockDelayMS);
|
||||
|
||||
if (this->doReadLock)
|
||||
{
|
||||
if(this->doTry)
|
||||
{
|
||||
this->lockSuccess = this->lock->tryReadLock();
|
||||
if (this->lockSuccess)
|
||||
this->lockTimestamp.setToNow();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lock->readLock();
|
||||
this->lockTimestamp.setToNow();
|
||||
this->lockSuccess = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this->doTry)
|
||||
{
|
||||
this->lockSuccess = this->lock->tryWriteLock();
|
||||
if (this->lockSuccess)
|
||||
this->lockTimestamp.setToNow();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lock->writeLock();
|
||||
this->lockTimestamp.setToNow();
|
||||
this->lockSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
// delay between lock and unlock for random execution order of the locking,
|
||||
// is necessary for a good test
|
||||
sleepMS(this->sleepTimeMS);
|
||||
|
||||
if (this->lockSuccess)
|
||||
{
|
||||
this->unlockTimestamp.setToNow();
|
||||
this->lock->unlock();
|
||||
this->unlockSuccess = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void sortThreadsInLockTimestamp(TestLockThread* threads, Time* startTime);
|
||||
void checkRandomRuntime(TestLockThread* threads, int runtimeMS);
|
||||
void checkRandomExecutionOrder(TestLockThread* threads);
|
||||
void checkRandomExecutionOrderReader(TestLockThread* threads, int threadID);
|
||||
void checkRandomExecutionOrderWriter(TestLockThread* threads, int threadID);
|
||||
};
|
||||
|
||||
1140
common/tests/TestSerialization.cpp
Normal file
1140
common/tests/TestSerialization.cpp
Normal file
File diff suppressed because it is too large
Load Diff
20
common/tests/TestSocket.cpp
Normal file
20
common/tests/TestSocket.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <common/net/sock/Socket.cpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
class TestSocket : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(TestSocket, endpointAddrToStrSockaddr)
|
||||
{
|
||||
std::string addr = "10.20.30.40";
|
||||
short port = 1234;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
sin.sin_port = htons(port);
|
||||
EXPECT_EQ(1, inet_pton(AF_INET, addr.c_str(), &sin.sin_addr));
|
||||
EXPECT_EQ(addr + ":" + std::to_string(port), Socket::endpointAddrToStr(&sin));
|
||||
}
|
||||
|
||||
90
common/tests/TestStorageTk.cpp
Normal file
90
common/tests/TestStorageTk.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <common/toolkit/StorageTk.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// full set of characters allowed in path components, properly escaped as by /proc/mounts
|
||||
#define FULL_SET "\001\002\003\004\005\006\007\010\\011\\012\013\014\015\016\017\020\021" \
|
||||
"\022\023\024\025\026\027\030\031\032\033\034\035\036\037\\040!\"#$%&'()*+,-.0123456789:;<=>?" \
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\134]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204" \
|
||||
"\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233" \
|
||||
"\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262" \
|
||||
"\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311" \
|
||||
"\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340" \
|
||||
"\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367" \
|
||||
"\370\371\372\373\374\375\376\377"
|
||||
#define FULL_SET_RAW "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021" \
|
||||
"\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040!\"#$%&'()*+,-.0123456789:;<=>?" \
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\134]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204" \
|
||||
"\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233" \
|
||||
"\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262" \
|
||||
"\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311" \
|
||||
"\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340" \
|
||||
"\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367" \
|
||||
"\370\371\372\373\374\375\376\377"
|
||||
|
||||
TEST(StorageTk, findMountedPrefix)
|
||||
{
|
||||
static const char* inputFile =
|
||||
"/dev/root / tmpfs rw 0 0\n"
|
||||
"/dev/sda1 /test/foo/bar xfs rw 0 0\n"
|
||||
"/dev/sda1 /test/fo ext4 rw 0 0\n"
|
||||
"/dev/sda1 /test/" FULL_SET " ext4 rw 0 0\n"
|
||||
"/dev/sda1 /test/foo ext4 rw 0 0\n";
|
||||
|
||||
{
|
||||
std::stringstream file;
|
||||
ASSERT_FALSE(StorageTk::findLongestMountedPrefix("", file).first);
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file;
|
||||
ASSERT_FALSE(StorageTk::findLongestMountedPrefix("relative", file).first);
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file;
|
||||
file.setstate(std::stringstream::failbit);
|
||||
ASSERT_FALSE(StorageTk::findLongestMountedPrefix("/", file).first);
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file;
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test", file);
|
||||
ASSERT_FALSE(res.first);
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file(inputFile);
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test/foo1", file);
|
||||
ASSERT_TRUE(res.first);
|
||||
ASSERT_EQ(res.second, (Mount{"/dev/root", "/", "tmpfs"}));
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file(inputFile);
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test/foo/bar/baz", file);
|
||||
ASSERT_TRUE(res.first);
|
||||
ASSERT_EQ(res.second, (Mount{"/dev/sda1", "/test/foo/bar", "xfs"}));
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file(inputFile);
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test/foo", file);
|
||||
ASSERT_TRUE(res.first);
|
||||
ASSERT_EQ(res.second, (Mount{"/dev/sda1", "/test/foo", "ext4"}));
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file(inputFile);
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test/" FULL_SET_RAW, file);
|
||||
ASSERT_TRUE(res.first);
|
||||
ASSERT_EQ(res.second, (Mount{"/dev/sda1", "/test/" FULL_SET_RAW, "ext4"}));
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream file(inputFile);
|
||||
auto res = StorageTk::findLongestMountedPrefix("/test/" FULL_SET_RAW "/sub", file);
|
||||
ASSERT_TRUE(res.first);
|
||||
ASSERT_EQ(res.second, (Mount{"/dev/sda1", "/test/" FULL_SET_RAW, "ext4"}));
|
||||
}
|
||||
}
|
||||
15
common/tests/TestStringTk.cpp
Normal file
15
common/tests/TestStringTk.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <common/toolkit/StringTk.h>
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(StringTk, implode)
|
||||
{
|
||||
EXPECT_EQ(std::string(""), StringTk::implode(",", std::vector<int>()));
|
||||
EXPECT_EQ(std::string("1"), StringTk::implode(",", std::vector<int>({1})));
|
||||
EXPECT_EQ(std::string("1,2,3"), StringTk::implode(",", std::vector<int>({1,2,3})));
|
||||
}
|
||||
40
common/tests/TestStripePattern.cpp
Normal file
40
common/tests/TestStripePattern.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <common/storage/striping/StripePattern.h>
|
||||
#include <common/storage/striping/Raid0Pattern.h>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
class Raid0PatternTest : public testing::TestWithParam<unsigned>
|
||||
{
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Name, Raid0PatternTest,
|
||||
::testing::Values(
|
||||
64*1024,
|
||||
1024*1024*1024
|
||||
)
|
||||
);
|
||||
|
||||
TEST_P(Raid0PatternTest, chunkSizes)
|
||||
{
|
||||
const auto chunkSize = GetParam();
|
||||
const auto targetPattern = std::vector<uint16_t>({0,1,2,3});
|
||||
const Raid0Pattern p(chunkSize, targetPattern);
|
||||
|
||||
ASSERT_EQ(p.getChunkSize(), chunkSize);
|
||||
|
||||
for(size_t i=0; i<10*targetPattern.size(); ++i) {
|
||||
|
||||
const auto chunkPos = int64_t(i) * chunkSize;
|
||||
const auto chunkEnd = chunkPos + chunkSize -1;
|
||||
|
||||
ASSERT_EQ(p.getStripeTargetIndex(chunkPos), i % targetPattern.size());
|
||||
ASSERT_EQ(p.getStripeTargetIndex(chunkEnd), i % targetPattern.size());
|
||||
|
||||
|
||||
ASSERT_EQ(p.getChunkStart(chunkPos), chunkPos);
|
||||
ASSERT_EQ(p.getChunkStart(chunkEnd), chunkPos);
|
||||
}
|
||||
}
|
||||
|
||||
18
common/tests/TestTargetCapacityPools.cpp
Normal file
18
common/tests/TestTargetCapacityPools.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <common/nodes/TargetCapacityPools.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(TargetCapacityPools, interdomainWithEmptyGroups)
|
||||
{
|
||||
TargetCapacityPools pools(false, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0});
|
||||
|
||||
pools.addOrUpdate(1, NumNodeID(1), CapacityPool_NORMAL);
|
||||
// moves target from LOW to NORMAL, must remove the NORMAL group from chooser
|
||||
pools.addOrUpdate(1, NumNodeID(1), CapacityPool_LOW);
|
||||
|
||||
std::vector<uint16_t> chosen;
|
||||
pools.chooseTargetsInterdomain(4, 1, &chosen);
|
||||
|
||||
EXPECT_EQ(chosen.size(), 1u);
|
||||
ASSERT_EQ(chosen[0], 1);
|
||||
}
|
||||
68
common/tests/TestTimerQueue.cpp
Normal file
68
common/tests/TestTimerQueue.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <common/components/TimerQueue.h>
|
||||
#include <common/threading/Barrier.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TestTimerQueue : public ::testing::Test {
|
||||
protected:
|
||||
std::unique_ptr<TimerQueue> queue;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
queue.reset(new TimerQueue(0, 20));
|
||||
queue->start();
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
struct EnqueueCancelFn
|
||||
{
|
||||
AtomicSizeT* count;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
count->increase();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_F(TestTimerQueue, enqueueCancel)
|
||||
{
|
||||
AtomicSizeT count(0);
|
||||
|
||||
auto handle = queue->enqueue(std::chrono::milliseconds(100), EnqueueCancelFn{&count});
|
||||
handle.cancel();
|
||||
|
||||
sleep(1);
|
||||
ASSERT_EQ(count.read(), 0u);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct EnqueueManyLongFn
|
||||
{
|
||||
void operator()(AtomicSizeT& count)
|
||||
{
|
||||
sleep(1);
|
||||
count.increase();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_F(TestTimerQueue, enqueueManyLong)
|
||||
{
|
||||
AtomicSizeT count(0);
|
||||
EnqueueManyLongFn fn;
|
||||
|
||||
for (int i = 0; i < 42; i++)
|
||||
queue->enqueue(
|
||||
std::chrono::milliseconds(10),
|
||||
std::bind(&EnqueueManyLongFn::operator(), &fn, std::ref(count)));
|
||||
|
||||
Time begin;
|
||||
while (count.read() != 42)
|
||||
sleep(1);
|
||||
|
||||
Time end;
|
||||
|
||||
ASSERT_LT(end.elapsedSinceMS(&begin), 20 * 1000u);
|
||||
}
|
||||
33
common/tests/TestUiTk.cpp
Normal file
33
common/tests/TestUiTk.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <common/toolkit/UiTk.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
bool testQuestion(const std::string& answer, boost::optional<bool> defaultAnswer=boost::none)
|
||||
{
|
||||
std::stringstream input(answer);
|
||||
return uitk::userYNQuestion("Test", defaultAnswer, input);
|
||||
}
|
||||
|
||||
TEST(UiTk, userYNQuestion)
|
||||
{
|
||||
// basic input
|
||||
ASSERT_TRUE( testQuestion("Y"));
|
||||
ASSERT_FALSE(testQuestion("N"));
|
||||
|
||||
ASSERT_TRUE( testQuestion("y"));
|
||||
ASSERT_FALSE(testQuestion("n"));
|
||||
|
||||
ASSERT_TRUE( testQuestion("Yes"));
|
||||
ASSERT_FALSE(testQuestion("No"));
|
||||
|
||||
// default answers
|
||||
ASSERT_TRUE( testQuestion("", true));
|
||||
ASSERT_FALSE(testQuestion("", false));
|
||||
|
||||
ASSERT_TRUE( testQuestion("Y", false));
|
||||
ASSERT_TRUE( testQuestion("Y", false));
|
||||
ASSERT_FALSE(testQuestion("N", true));
|
||||
ASSERT_FALSE(testQuestion("N", true));
|
||||
}
|
||||
151
common/tests/TestUnitTk.cpp
Normal file
151
common/tests/TestUnitTk.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <common/toolkit/UnitTk.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(UnitTk, gigabyteToByte)
|
||||
{
|
||||
double gbValue = 1.0;
|
||||
int64_t byteValueExpected = 1073741824LL;
|
||||
int64_t byteValueCalc = UnitTk::gibibyteToByte(gbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
gbValue = 10.0;
|
||||
byteValueExpected = 10737418240LL;
|
||||
byteValueCalc = UnitTk::gibibyteToByte(gbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
gbValue = 10.598;
|
||||
byteValueExpected = 11379515850LL;
|
||||
|
||||
byteValueCalc = UnitTk::gibibyteToByte(gbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
}
|
||||
|
||||
TEST(UnitTk, megabyteToByte)
|
||||
{
|
||||
double mbValue = 1.0;
|
||||
int64_t byteValueExpected = 1048576LL;
|
||||
int64_t byteValueCalc = UnitTk::mebibyteToByte(mbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
mbValue = 10.0;
|
||||
byteValueExpected = 10485760LL;
|
||||
byteValueCalc = UnitTk::mebibyteToByte(mbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
mbValue = 10.598;
|
||||
byteValueExpected = 11112808LL;
|
||||
byteValueCalc = UnitTk::mebibyteToByte(mbValue);;
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
}
|
||||
|
||||
TEST(UnitTk, kilobyteToByte)
|
||||
{
|
||||
double kbValue = 1.0;
|
||||
int64_t byteValueExpected = 1024LL;
|
||||
int64_t byteValueCalc = UnitTk::kibibyteToByte(kbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
kbValue = 10.0;
|
||||
byteValueExpected = 10240LL;
|
||||
byteValueCalc = UnitTk::kibibyteToByte(kbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
kbValue = 10.598;
|
||||
byteValueExpected = 10852LL;
|
||||
byteValueCalc = UnitTk::kibibyteToByte(kbValue);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
}
|
||||
|
||||
TEST(UnitTk, byteToXbyte)
|
||||
{
|
||||
std::string unit;
|
||||
int64_t value = 2048LL;
|
||||
double valueExpected = 2.0;
|
||||
double valueCalc = UnitTk::byteToXbyte(value, &unit);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("KiB"), 0);
|
||||
|
||||
value = 10240LL;
|
||||
valueExpected = 10.0;
|
||||
valueCalc = UnitTk::byteToXbyte(value, &unit);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("KiB"), 0);
|
||||
|
||||
value = 10843LL;
|
||||
valueExpected = 10.6;
|
||||
valueCalc = UnitTk::byteToXbyte(value, &unit, true);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("KiB"), 0);
|
||||
|
||||
value = 1073741824LL;
|
||||
valueExpected = 1024.0;
|
||||
valueCalc = UnitTk::byteToXbyte(value, &unit);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("MiB"), 0);
|
||||
|
||||
value = 10737418240LL;
|
||||
valueExpected = 10.0;
|
||||
valueCalc = UnitTk::byteToXbyte(value, &unit);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("GiB"), 0);
|
||||
|
||||
value = 11446087843LL;
|
||||
valueExpected = 10.7;
|
||||
valueCalc = UnitTk::byteToXbyte(value, &unit, true);
|
||||
ASSERT_EQ(valueExpected, valueCalc);
|
||||
ASSERT_EQ(unit.compare("GiB"), 0);
|
||||
}
|
||||
|
||||
TEST(UnitTk, xbyteToByte)
|
||||
{
|
||||
std::string unit = "KiB";
|
||||
double value = 1.0;
|
||||
int64_t byteValueExpected = 1024LL;
|
||||
int64_t byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.0;
|
||||
byteValueExpected = 10240LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.598;
|
||||
byteValueExpected = 10852LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
|
||||
unit = "MiB";
|
||||
value = 1.0;
|
||||
byteValueExpected = 1048576LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.0;
|
||||
byteValueExpected = 10485760LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.598;
|
||||
byteValueExpected = 11112808LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
|
||||
unit = "GiB";
|
||||
value = 1.0;
|
||||
byteValueExpected = 1073741824LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.0;
|
||||
byteValueExpected = 10737418240LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
|
||||
value = 10.598;
|
||||
byteValueExpected = 11379515850LL;
|
||||
byteValueCalc = UnitTk::xbyteToByte(value, unit);
|
||||
ASSERT_EQ(byteValueExpected, byteValueCalc);
|
||||
}
|
||||
Reference in New Issue
Block a user