Added test cases for Cache

This commit is contained in:
Sebastian Messmer 2015-04-28 11:56:07 +02:00
parent d589910b0d
commit cb402fd14b
8 changed files with 247 additions and 47 deletions

View File

@ -1,14 +0,0 @@
#include <google/gtest/gtest.h>
#include "../../../../implementations/caching/cache/Cache.h"
using ::testing::Test;
using namespace blockstore::caching;
class CacheTest: public Test {
public:
Cache<int, int> cache;
};
//TODO Write test cases

View File

@ -0,0 +1,34 @@
#include <google/gtest/gtest.h>
#include <memory>
#include "../../../../implementations/caching/cache/Cache.h"
#include "testutils/MinimalKeyType.h"
#include "testutils/CopyableMovableValueType.h"
using namespace blockstore::caching;
using ::testing::Test;
using std::unique_ptr;
using std::make_unique;
//Test that Cache uses a move constructor for Value if possible
class CacheTest_MoveConstructor: public Test {
public:
CacheTest_MoveConstructor() {
CopyableMovableValueType::numCopyConstructorCalled = 0;
cache = make_unique<Cache<MinimalKeyType, CopyableMovableValueType>>();
}
unique_ptr<Cache<MinimalKeyType, CopyableMovableValueType>> cache;
};
TEST_F(CacheTest_MoveConstructor, MoveIntoCache) {
cache->push(MinimalKeyType::create(0), CopyableMovableValueType(2));
CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled);
}
TEST_F(CacheTest_MoveConstructor, CopyIntoCache) {
CopyableMovableValueType value(2);
cache->push(MinimalKeyType::create(0), value);
CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled);
}

View File

@ -0,0 +1,133 @@
#include "testutils/CacheTest.h"
#include "../../../../implementations/caching/cache/Cache.h"
#include "testutils/MinimalKeyType.h"
#include "testutils/MinimalValueType.h"
using ::testing::Test;
using namespace blockstore::caching;
class CacheTest_PushAndPop: public CacheTest {};
TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_EmptyCache) {
EXPECT_EQ(boost::none, pop(10));
}
TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_NonEmptyCache) {
push(9, 10);
EXPECT_EQ(boost::none, pop(10));
}
TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_FullCache) {
//Add a lot of even numbered keys
for (int i = 0; i < Cache::MAX_ENTRIES; ++i) {
push(2*i, 2*i);
}
//Request an odd numbered key
EXPECT_EQ(boost::none, pop(9));
}
TEST_F(CacheTest_PushAndPop, OneEntry) {
push(10, 20);
EXPECT_EQ(20, pop(10).value());
}
TEST_F(CacheTest_PushAndPop, MultipleEntries) {
push(10, 20);
push(20, 30);
push(30, 40);
EXPECT_EQ(30, pop(20).value());
EXPECT_EQ(20, pop(10).value());
EXPECT_EQ(40, pop(30).value());
}
TEST_F(CacheTest_PushAndPop, FullCache) {
for(int i = 0; i < Cache::MAX_ENTRIES; ++i) {
push(i, 2*i);
}
for(int i = 0; i < Cache::MAX_ENTRIES; ++i) {
EXPECT_EQ(2*i, pop(i).value());
}
}
TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopOrdered) {
for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) {
push(i, 2*i);
}
for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) {
push(i, 2*i);
}
for(int i = 0; i < Cache::MAX_ENTRIES; ++i) {
EXPECT_EQ(2*i, pop(i).value());
}
}
TEST_F(CacheTest_PushAndPop, FullCache_PushOrdered_PopNonOrdered) {
for(int i = 0; i < Cache::MAX_ENTRIES; ++i) {
push(i, 2*i);
}
for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) {
EXPECT_EQ(2*i, pop(i).value());
}
for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) {
EXPECT_EQ(2*i, pop(i).value());
}
}
int roundDownToEven(int number) {
if (number % 2 == 0) {
return number;
} else {
return number - 1;
}
}
int roundDownToOdd(int number) {
if (number % 2 != 0) {
return number;
} else {
return number - 1;
}
}
TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopNonOrdered) {
for(int i = roundDownToEven(Cache::MAX_ENTRIES - 1); i >= 0; i -= 2) {
push(i, 2*i);
}
for(int i = 1; i < Cache::MAX_ENTRIES; i += 2) {
push(i, 2*i);
}
for(int i = roundDownToOdd(Cache::MAX_ENTRIES-1); i >= 0; i -= 2) {
EXPECT_EQ(2*i, pop(i).value());
}
for(int i = 0; i < Cache::MAX_ENTRIES; i += 2) {
EXPECT_EQ(2*i, pop(i).value());
}
}
TEST_F(CacheTest_PushAndPop, MoreThanFullCache) {
for(int i = 0; i < Cache::MAX_ENTRIES + 2; ++i) {
push(i, 2*i);
}
//Check that the oldest two elements got deleted automatically
EXPECT_EQ(boost::none, pop(0));
EXPECT_EQ(boost::none, pop(1));
//Check the other elements are still there
for(int i = 2; i < Cache::MAX_ENTRIES + 2; ++i) {
EXPECT_EQ(2*i, pop(i).value());
}
}
TEST_F(CacheTest_PushAndPop, AfterTimeout) {
constexpr double TIMEOUT1_SEC = Cache::MAX_LIFETIME_SEC * 3/4;
constexpr double TIMEOUT2_SEC = Cache::PURGE_LIFETIME_SEC * 3/4;
static_assert(TIMEOUT1_SEC + TIMEOUT2_SEC > Cache::MAX_LIFETIME_SEC, "Ensure that our chosen timeouts push the first entry out of the cache");
push(10, 20);
boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast<int>(1000 * TIMEOUT1_SEC)));
push(20, 30);
boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast<int>(1000 * TIMEOUT2_SEC)));
EXPECT_EQ(boost::none, pop(10));
EXPECT_EQ(30, pop(20).value());
}

View File

@ -2,6 +2,7 @@
#include <memory>
#include "../../../../implementations/caching/cache/QueueMap.h"
#include "testutils/MinimalKeyType.h"
#include "testutils/CopyableMovableValueType.h"
using namespace blockstore::caching;
@ -9,56 +10,38 @@ using ::testing::Test;
using std::unique_ptr;
using std::make_unique;
class CopyableValueType {
public:
static int numCopyConstructorCalled;
CopyableValueType(int value): _value(value) {}
CopyableValueType(const CopyableValueType &rhs): CopyableValueType(rhs._value) {
++numCopyConstructorCalled;
}
CopyableValueType(CopyableValueType &&rhs): CopyableValueType(rhs._value) {
//Don't increase numCopyConstructorCalled
}
int value() const {
return _value;
}
private:
int _value;
};
int CopyableValueType::numCopyConstructorCalled = 0;
//Test that QueueMap uses a move constructor for Value if possible
class QueueMapTest_MoveConstructor: public Test {
public:
QueueMapTest_MoveConstructor() {
CopyableValueType::numCopyConstructorCalled = 0;
map = make_unique<QueueMap<MinimalKeyType, CopyableValueType>>();
CopyableMovableValueType::numCopyConstructorCalled = 0;
map = make_unique<QueueMap<MinimalKeyType, CopyableMovableValueType>>();
}
unique_ptr<QueueMap<MinimalKeyType, CopyableValueType>> map;
unique_ptr<QueueMap<MinimalKeyType, CopyableMovableValueType>> map;
};
TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_MoveIntoMap) {
map->push(MinimalKeyType::create(0), CopyableValueType(2));
CopyableValueType val = map->pop().value();
EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled);
map->push(MinimalKeyType::create(0), CopyableMovableValueType(2));
CopyableMovableValueType val = map->pop().value();
EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled);
}
TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_MoveIntoMap) {
map->push(MinimalKeyType::create(0), CopyableValueType(2));
CopyableValueType val = map->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(0, CopyableValueType::numCopyConstructorCalled);
map->push(MinimalKeyType::create(0), CopyableMovableValueType(2));
CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled);
}
TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_CopyIntoMap) {
CopyableValueType value(2);
CopyableMovableValueType value(2);
map->push(MinimalKeyType::create(0), value);
CopyableValueType val = map->pop().value();
EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled);
CopyableMovableValueType val = map->pop().value();
EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled);
}
TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_CopyIntoMap) {
CopyableValueType value(2);
CopyableMovableValueType value(2);
map->push(MinimalKeyType::create(0), value);
CopyableValueType val = map->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(1, CopyableValueType::numCopyConstructorCalled);
CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value();
EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled);
}

View File

@ -0,0 +1,13 @@
#include "CacheTest.h"
void CacheTest::push(int key, int value) {
return _cache.push(MinimalKeyType::create(key), MinimalValueType::create(value));
}
boost::optional<int> CacheTest::pop(int key) {
boost::optional<MinimalValueType> entry = _cache.pop(MinimalKeyType::create(key));
if (!entry) {
return boost::none;
}
return entry->value();
}

View File

@ -0,0 +1,25 @@
#pragma once
#ifndef BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_
#define BLOCKS_MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_
#include <google/gtest/gtest.h>
#include "../../../../../implementations/caching/cache/Cache.h"
#include "MinimalKeyType.h"
#include "MinimalValueType.h"
#include <boost/optional.hpp>
// This class is a parent class for tests on QueueMap.
// It offers functions to work with a QueueMap test object which is built using types having only the minimal type requirements.
// Furthermore, the class checks that there are no memory leaks left after destructing the QueueMap (by counting leftover instances of Keys/Values).
class CacheTest: public ::testing::Test {
public:
void push(int key, int value);
boost::optional<int> pop(int key);
using Cache = blockstore::caching::Cache<MinimalKeyType, MinimalValueType>;
private:
Cache _cache;
};
#endif

View File

@ -0,0 +1,3 @@
#include "CopyableMovableValueType.h"
int CopyableMovableValueType::numCopyConstructorCalled = 0;

View File

@ -0,0 +1,23 @@
#pragma once
#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_
#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_
class CopyableMovableValueType {
public:
static int numCopyConstructorCalled;
CopyableMovableValueType(int value): _value(value) {}
CopyableMovableValueType(const CopyableMovableValueType &rhs): CopyableMovableValueType(rhs._value) {
++numCopyConstructorCalled;
}
CopyableMovableValueType(CopyableMovableValueType &&rhs): CopyableMovableValueType(rhs._value) {
//Don't increase numCopyConstructorCalled
}
int value() const {
return _value;
}
private:
int _value;
};
#endif