// ----------------------------------------------------------------------
// File: queueing.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* qclient - A simple redis C++ client with support for redirects *
* Copyright (C) 2016 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include
#include "qclient/queueing/ThreadSafeQueue.hh"
#include "qclient/queueing/AttachableQueue.hh"
#include "qclient/queueing/RingBuffer.hh"
#include "qclient/queueing/LastNSet.hh"
#include "qclient/queueing/LastNMap.hh"
using namespace qclient;
class Coord {
public:
Coord() {}
Coord(int a, int b) : x(a), y(b) {}
int x = -1;
int y = -1;
};
template
class Thread_Safe_Queue : public testing::Test {
protected:
T queue;
};
typedef ::testing::Types<
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue, ThreadSafeQueue, ThreadSafeQueue,
ThreadSafeQueue> Implementations;
TYPED_TEST_SUITE(Thread_Safe_Queue, Implementations);
TYPED_TEST(Thread_Safe_Queue, BasicSanity) {
ASSERT_TRUE(this->queue.empty());
ASSERT_EQ(this->queue.getNextSequenceNumber(), 0);
ASSERT_EQ(0, this->queue.emplace_back(1, 2));
ASSERT_EQ(this->queue.getNextSequenceNumber(), 1);
ASSERT_FALSE(this->queue.empty());
auto it = this->queue.begin();
ASSERT_EQ(it.seq(), 0);
Coord *coord = &it.item();
ASSERT_EQ(coord->x, 1);
ASSERT_EQ(coord->y, 2);
it.next();
ASSERT_EQ(it.seq(), 1);
ASSERT_EQ(0, this->queue.pop_front());
ASSERT_TRUE(this->queue.empty());
ASSERT_EQ(1, this->queue.emplace_back(2, 3));
ASSERT_EQ(this->queue.getNextSequenceNumber(), 2);
ASSERT_FALSE(this->queue.empty());
coord = &it.item();
ASSERT_EQ(coord->x, 2);
ASSERT_EQ(coord->y, 3);
it.next();
ASSERT_EQ(it.seq(), 2);
ASSERT_EQ(1, this->queue.pop_front());
ASSERT_TRUE(this->queue.empty());
for(int i = 0; i < 100; i++) {
ASSERT_EQ(2 + i, this->queue.emplace_back(i*i, i*i+1));
ASSERT_EQ(this->queue.getNextSequenceNumber(), i+3);
ASSERT_FALSE(this->queue.empty());
}
for(int i = 0; i < 100; i++) {
coord = &it.item();
ASSERT_EQ(coord->x, i*i);
ASSERT_EQ(coord->y, i*i+1);
it.next();
ASSERT_EQ(it.seq(), 3+i);
ASSERT_EQ(2+i, this->queue.pop_front());
}
ASSERT_TRUE(this->queue.empty());
}
class Accumulator {
public:
void add(int &&val) {
sum += val;
}
int getSum() const {
return sum;
}
private:
int sum = 0;
};
TEST(AttachableQueue, BasicSanity) {
AttachableQueue queue;
// Detached mode, acts as a queue
queue.emplace_back(3);
ASSERT_EQ(queue.size(), 1u);
ASSERT_EQ(queue.front(), 3);
queue.pop_front();
ASSERT_EQ(queue.size(), 0u);
queue.emplace_back(4);
queue.emplace_back(5);
queue.emplace_back(5);
ASSERT_EQ(queue.size(), 3u);
ASSERT_EQ(queue.front(), 4);
queue.pop_front();
ASSERT_EQ(queue.size(), 2u);
// Attach callback
using std::placeholders::_1;
Accumulator acu;
queue.attach(std::bind(&Accumulator::add, &acu, _1));
ASSERT_EQ(queue.size(), 0u);
ASSERT_EQ(acu.getSum(), 10);
queue.emplace_back(3);
ASSERT_EQ(acu.getSum(), 13);
ASSERT_EQ(queue.size(), 0u);
queue.detach();
queue.emplace_back(7);
ASSERT_EQ(acu.getSum(), 13);
ASSERT_EQ(queue.size(), 1u);
ASSERT_EQ(queue.front(), 7);
queue.attach(std::bind(&Accumulator::add, &acu, _1));
ASSERT_EQ(queue.size(), 0u);
ASSERT_EQ(acu.getSum(), 20);
}
TEST(RingBuffer, BasicSanity) {
RingBuffer ringBuffer(3);
ASSERT_EQ(ringBuffer.getNextToEvict(), "");
ASSERT_FALSE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("aaa");
ASSERT_EQ(ringBuffer.getNextToEvict(), "");
ASSERT_FALSE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("bbb");
ASSERT_EQ(ringBuffer.getNextToEvict(), "");
ASSERT_FALSE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("ccc");
ASSERT_EQ(ringBuffer.getNextToEvict(), "aaa");
ASSERT_TRUE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("ddd");
ASSERT_EQ(ringBuffer.getNextToEvict(), "bbb");
ASSERT_TRUE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("eee");
ASSERT_EQ(ringBuffer.getNextToEvict(), "ccc");
ASSERT_TRUE(ringBuffer.hasRolledOver());
ringBuffer.emplace_back("eee");
ASSERT_EQ(ringBuffer.getNextToEvict(), "ddd");
ASSERT_TRUE(ringBuffer.hasRolledOver());
}
TEST(LastNSet, BasicSanity) {
LastNSet lastSet(3);
ASSERT_FALSE(lastSet.query(""));
lastSet.emplace("aaa");
ASSERT_TRUE(lastSet.query("aaa"));
ASSERT_FALSE(lastSet.query("bbb"));
ASSERT_FALSE(lastSet.query("ccc"));
lastSet.emplace("bbb");
ASSERT_TRUE(lastSet.query("aaa"));
ASSERT_TRUE(lastSet.query("bbb"));
ASSERT_FALSE(lastSet.query("ccc"));
lastSet.emplace("ccc");
ASSERT_TRUE(lastSet.query("aaa"));
ASSERT_TRUE(lastSet.query("bbb"));
ASSERT_TRUE(lastSet.query("ccc"));
lastSet.emplace("ddd");
ASSERT_FALSE(lastSet.query("aaa"));
ASSERT_TRUE(lastSet.query("bbb"));
ASSERT_TRUE(lastSet.query("ccc"));
ASSERT_TRUE(lastSet.query("ddd"));
ASSERT_FALSE(lastSet.query(""));
}
TEST(LastNMap, BasicSanity) {
LastNMap lastMap(3);
lastMap.insert("a", 99);
int32_t val;
ASSERT_TRUE(lastMap.query("a", val));
ASSERT_EQ(val, 99);
lastMap.insert("a", 88);
ASSERT_TRUE(lastMap.query("a", val));
ASSERT_EQ(val, 88);
lastMap.insert("b", 77);
ASSERT_TRUE(lastMap.query("a", val));
ASSERT_EQ(val, 88);
ASSERT_TRUE(lastMap.query("b", val));
ASSERT_EQ(val, 77);
lastMap.insert("c", 66);
ASSERT_TRUE(lastMap.query("a", val));
ASSERT_EQ(val, 88);
ASSERT_TRUE(lastMap.query("b", val));
ASSERT_EQ(val, 77);
ASSERT_TRUE(lastMap.query("c", val));
ASSERT_EQ(val, 66);
lastMap.insert("d", 55);
ASSERT_FALSE(lastMap.query("a", val));
ASSERT_TRUE(lastMap.query("b", val));
ASSERT_EQ(val, 77);
ASSERT_TRUE(lastMap.query("c", val));
ASSERT_EQ(val, 66);
ASSERT_TRUE(lastMap.query("d", val));
ASSERT_EQ(val, 55);
}