danicoin/tests/UnitTests/TestMessageQueue.cpp
2016-01-18 15:33:29 +00:00

279 lines
8.9 KiB
C++

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "gtest/gtest.h"
#include <thread>
#include <iostream>
#include "System/ContextGroup.h"
#include "System/Dispatcher.h"
#include "System/Event.h"
#include "CryptoNoteCore/MessageQueue.h"
#include "CryptoNoteCore/BlockchainMessages.h"
#include "CryptoNoteCore/IntrusiveLinkedList.h"
#include "CryptoNoteCore/CryptoNoteTools.h"
using namespace CryptoNote;
class MessageQueueTest : public testing::Test {
public:
MessageQueueTest() : contextGroup(dispatcher) {}
bool addMessageQueue(MessageQueue<BlockchainMessage>& messageQueue);
bool removeMessageQueue(MessageQueue<BlockchainMessage>& messageQueue);
void sendBlockchainMessage(const BlockchainMessage& message);
void interruptBlockchainMessageWaiting();
void SetUp() override;
void TearDown() override;
protected:
System::Dispatcher dispatcher;
System::ContextGroup contextGroup;
IntrusiveLinkedList<MessageQueue<BlockchainMessage>> blockchainMessageQueueList;
};
bool MessageQueueTest::addMessageQueue(MessageQueue<BlockchainMessage>& messageQueue) {
return blockchainMessageQueueList.insert(messageQueue);
}
bool MessageQueueTest::removeMessageQueue(MessageQueue<BlockchainMessage>& messageQueue) {
return blockchainMessageQueueList.remove(messageQueue);
}
void MessageQueueTest::sendBlockchainMessage(const BlockchainMessage& message) {
for (IntrusiveLinkedList<MessageQueue<BlockchainMessage>>::iterator iter = blockchainMessageQueueList.begin(); iter != blockchainMessageQueueList.end(); ++iter) {
iter->push(message);
}
}
void MessageQueueTest::interruptBlockchainMessageWaiting() {
for (IntrusiveLinkedList<MessageQueue<BlockchainMessage>>::iterator iter = blockchainMessageQueueList.begin(); iter != blockchainMessageQueueList.end(); ++iter) {
iter->stop();
}
}
void MessageQueueTest::SetUp() {
ASSERT_TRUE(blockchainMessageQueueList.empty());
}
void MessageQueueTest::TearDown() {
ASSERT_TRUE(blockchainMessageQueueList.empty());
}
TEST_F(MessageQueueTest, singleNewBlockMessage) {
MessageQueue<BlockchainMessage> queue(dispatcher);
MesageQueueGuard<MessageQueueTest, BlockchainMessage> guard(*this, queue);
Crypto::Hash randomHash;
for (uint8_t& i : randomHash.data) {
i = rand();
}
contextGroup.spawn([&]() {
const BlockchainMessage& m = queue.front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::NEW_BLOCK_MESSAGE);
Crypto::Hash h;
ASSERT_TRUE(m.getNewBlockHash(h));
ASSERT_EQ(h, randomHash);
ASSERT_NO_THROW(queue.pop());
});
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(NewBlockMessage(randomHash))));
contextGroup.wait();
}
TEST_F(MessageQueueTest, singleNewAlternativeBlockMessage) {
MessageQueue<BlockchainMessage> queue(dispatcher);
MesageQueueGuard<MessageQueueTest, BlockchainMessage> guard(*this, queue);
Crypto::Hash randomHash;
for (uint8_t& i : randomHash.data) {
i = rand();
}
contextGroup.spawn([&]() {
const BlockchainMessage& m = queue.front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::NEW_ALTERNATIVE_BLOCK_MESSAGE);
Crypto::Hash h;
ASSERT_TRUE(m.getNewAlternativeBlockHash(h));
ASSERT_EQ(h, randomHash);
ASSERT_NO_THROW(queue.pop());
});
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(NewAlternativeBlockMessage(randomHash))));
contextGroup.wait();
}
TEST_F(MessageQueueTest, singleChainSwitchMessage) {
MessageQueue<BlockchainMessage> queue(dispatcher);
MesageQueueGuard<MessageQueueTest, BlockchainMessage> guard(*this, queue);
const size_t NUMBER_OF_BLOCKS = 10;
std::vector<Crypto::Hash> randomHashes;
for (size_t i = 0; i < NUMBER_OF_BLOCKS; ++i) {
Crypto::Hash randomHash;
for (uint8_t& j : randomHash.data) {
j = rand();
}
randomHashes.push_back(randomHash);
}
contextGroup.spawn([&]() {
const BlockchainMessage& m = queue.front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::CHAIN_SWITCH_MESSAGE);
std::vector<Crypto::Hash> res;
ASSERT_TRUE(m.getChainSwitch(res));
ASSERT_EQ(res, randomHashes);
ASSERT_NO_THROW(queue.pop());
});
std::vector<Crypto::Hash> copy = randomHashes;
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(ChainSwitchMessage(std::move(copy)))));
contextGroup.wait();
}
TEST_F(MessageQueueTest, manyMessagesOneListener) {
MessageQueue<BlockchainMessage> queue(dispatcher);
MesageQueueGuard<MessageQueueTest, BlockchainMessage> guard(*this, queue);
const size_t NUMBER_OF_BLOCKS = 10;
std::vector<Crypto::Hash> randomHashes;
for (size_t i = 0; i < NUMBER_OF_BLOCKS; ++i) {
Crypto::Hash randomHash;
for (uint8_t& j : randomHash.data) {
j = rand();
}
randomHashes.push_back(randomHash);
}
contextGroup.spawn([&]() {
for (size_t i = 0; i < NUMBER_OF_BLOCKS; ++i) {
const BlockchainMessage& m = queue.front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::NEW_BLOCK_MESSAGE);
Crypto::Hash h;
ASSERT_TRUE(m.getNewBlockHash(h));
ASSERT_EQ(h, randomHashes[i]);
ASSERT_NO_THROW(queue.pop());
}
});
for (auto h : randomHashes) {
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(NewBlockMessage(h))));
}
contextGroup.wait();
}
TEST_F(MessageQueueTest, manyMessagesManyListeners) {
const size_t NUMBER_OF_LISTENERS = 5;
std::array<std::unique_ptr<MessageQueue<BlockchainMessage>>, NUMBER_OF_LISTENERS> queues;
std::array<std::unique_ptr<MesageQueueGuard<MessageQueueTest, BlockchainMessage>>, NUMBER_OF_LISTENERS> quards;
for (size_t i = 0; i < NUMBER_OF_LISTENERS; ++i) {
queues[i] = std::unique_ptr<MessageQueue<BlockchainMessage>>(new MessageQueue<BlockchainMessage>(dispatcher));
quards[i] = std::unique_ptr<MesageQueueGuard<MessageQueueTest, BlockchainMessage>>(new MesageQueueGuard<MessageQueueTest, BlockchainMessage>(*this, *queues[i]));
}
const size_t NUMBER_OF_BLOCKS = 10;
std::vector<Crypto::Hash> randomHashes;
for (size_t i = 0; i < NUMBER_OF_BLOCKS; ++i) {
Crypto::Hash randomHash;
for (uint8_t& j : randomHash.data) {
j = rand();
}
randomHashes.push_back(randomHash);
}
contextGroup.spawn([&]() {
for (size_t i = 0; i < NUMBER_OF_LISTENERS; ++i) {
for (size_t j = 0; j < NUMBER_OF_BLOCKS; ++j) {
const BlockchainMessage& m = queues[i]->front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::NEW_BLOCK_MESSAGE);
Crypto::Hash h;
ASSERT_TRUE(m.getNewBlockHash(h));
ASSERT_EQ(h, randomHashes[j]);
ASSERT_NO_THROW(queues[i]->pop());
}
}
});
for (auto h : randomHashes) {
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(NewBlockMessage(h))));
}
contextGroup.wait();
}
TEST_F(MessageQueueTest, interruptWaiting) {
const size_t NUMBER_OF_LISTENERS = 5;
std::array<std::unique_ptr<MessageQueue<BlockchainMessage>>, NUMBER_OF_LISTENERS> queues;
std::array<std::unique_ptr<MesageQueueGuard<MessageQueueTest, BlockchainMessage>>, NUMBER_OF_LISTENERS> quards;
for (size_t i = 0; i < NUMBER_OF_LISTENERS; ++i) {
queues[i] = std::unique_ptr<MessageQueue<BlockchainMessage>>(new MessageQueue<BlockchainMessage>(dispatcher));
quards[i] = std::unique_ptr<MesageQueueGuard<MessageQueueTest, BlockchainMessage>>(new MesageQueueGuard<MessageQueueTest, BlockchainMessage>(*this, *queues[i]));
}
const size_t NUMBER_OF_BLOCKS = 10;
std::vector<Crypto::Hash> randomHashes;
for (size_t i = 0; i < NUMBER_OF_BLOCKS; ++i) {
Crypto::Hash randomHash;
for (uint8_t& j : randomHash.data) {
j = rand();
}
randomHashes.push_back(randomHash);
}
System::Event shutdownEvent(dispatcher);
contextGroup.spawn([&]() {
shutdownEvent.wait();
for (size_t i = 0; i < NUMBER_OF_LISTENERS; ++i) {
for (size_t j = 0; j < NUMBER_OF_BLOCKS; ++j) {
const BlockchainMessage& m = queues[i]->front();
ASSERT_EQ(m.getType(), BlockchainMessage::MessageType::NEW_BLOCK_MESSAGE);
Crypto::Hash h;
ASSERT_TRUE(m.getNewBlockHash(h));
ASSERT_EQ(h, randomHashes[j]);
ASSERT_NO_THROW(queues[i]->pop());
}
}
for (size_t i = 0; i < NUMBER_OF_LISTENERS; ++i) {
for (size_t j = 0; j < NUMBER_OF_BLOCKS; ++j) {
ASSERT_ANY_THROW(queues[i]->front());
ASSERT_ANY_THROW(queues[i]->pop());
}
}
});
for (auto h : randomHashes) {
ASSERT_NO_THROW(sendBlockchainMessage(BlockchainMessage(NewBlockMessage(h))));
}
interruptBlockchainMessageWaiting();
shutdownEvent.set();
contextGroup.wait();
}
TEST_F(MessageQueueTest, doubleAddQueueToList) {
MessageQueue<BlockchainMessage> queue(dispatcher);
ASSERT_TRUE(blockchainMessageQueueList.insert(queue));
ASSERT_FALSE(blockchainMessageQueueList.insert(queue));
ASSERT_TRUE(blockchainMessageQueueList.remove(queue));
ASSERT_FALSE(blockchainMessageQueueList.remove(queue));
}