g3log/g2log/test_unit/test_sink.cpp

165 lines
5.5 KiB
C++

/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
#include <iostream>
#include <atomic>
#include <vector>
#include <memory>
#include <thread>
#include <chrono>
#include <string>
#include "testing_helpers.h"
#include "g2logmessage.hpp"
#include "g2logworker.hpp"
#include "std2_make_unique.hpp"
using namespace testing_helpers;
using namespace std;
TEST(Sink, OneSink) {
using namespace g2;
AtomicBoolPtr flag = make_shared < atomic<bool >> (false);
AtomicIntPtr count = make_shared < atomic<int >> (0);
{
auto worker = g2::LogWorker::createWithNoSink();
auto handle = worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
EXPECT_FALSE(flag->load());
EXPECT_TRUE(0 == count->load());
LogMessagePtr message{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
message.get()->write().append("this message should trigger an atomic increment at the sink");
worker->save(message);
}
EXPECT_TRUE(flag->load());
EXPECT_TRUE(1 == count->load());
}
namespace {
typedef std::shared_ptr<std::atomic<bool >> AtomicBoolPtr;
typedef std::shared_ptr<std::atomic<int >> AtomicIntPtr;
typedef vector<AtomicBoolPtr> BoolList;
typedef vector<AtomicIntPtr> IntVector;
}
TEST(ConceptSink, OneHundredSinks) {
using namespace g2;
BoolList flags;
IntVector counts;
size_t NumberOfItems = 100;
for (size_t index = 0; index < NumberOfItems; ++index) {
flags.push_back(make_shared < atomic<bool >> (false));
counts.push_back(make_shared < atomic<int >> (0));
}
{
RestoreFileLogger logger{"./"};
g2::LogWorker* worker = logger._scope->get(); //g2LogWorker::createWithNoSink();
size_t index = 0;
for (auto& flag : flags) {
auto& count = counts[index++];
// ignore the handle
worker->addSink(std2::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
}
LOG(DEBUG) << "start message";
LogMessagePtr message1{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
LogMessagePtr message2{std2::make_unique<LogMessage>("test", 0, "test", DEBUG)};
auto& write1 = message1.get()->write();
write1.append("Hello to 100 receivers :)");
worker->save(message1);
auto& write2 = message2.get()->write();
write2.append("Hello to 100 receivers :)");
worker->save(message2);
LOG(INFO) << "end message";
logger.reset();
}
// at the curly brace above the ScopedLogger will go out of scope and all the
// 100 logging receivers will get their message to exit after all messages are
// are processed
size_t index = 0;
for (auto& flag : flags) {
auto& count = counts[index++];
ASSERT_TRUE(flag->load()) << ", count : " << (index - 1);
ASSERT_TRUE(4 == count->load()) << ", count : " << (index - 1);
}
cout << "test one hundred sinks is finished finished\n";
}
struct VoidReceiver {
std::atomic<int>* _atomicCounter;
explicit VoidReceiver(std::atomic<int>* counter) : _atomicCounter(counter){}
void receiveMsg(std::string msg){ /*ignored*/}
void incrementAtomic(){
(*_atomicCounter)++;
}
};
TEST(ConceptSink, VoidCall__NoCall_ExpectingNoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
}
EXPECT_EQ(counter, 0);
}
TEST(ConceptSink, VoidCall__OneCall_ExpectingOneAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
std::future<void> ignored = handle->call(&VoidReceiver::incrementAtomic);
}
EXPECT_EQ(counter, 1);
}
TEST(ConceptSink, VoidCall__TwoCalls_ExpectingTwoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<VoidReceiver>(&counter), &VoidReceiver::receiveMsg);
auto voidFuture1 = handle->call(&VoidReceiver::incrementAtomic);
auto voidFuture2 = handle->call(&VoidReceiver::incrementAtomic);
voidFuture1.wait();
EXPECT_TRUE(counter >= 1);
}
EXPECT_EQ(counter, 2);
}
struct IntReceiver {
std::atomic<int>* _atomicCounter;
explicit IntReceiver(std::atomic<int>* counter) : _atomicCounter(counter){}
void receiveMsg(std::string msg){ /*ignored*/}
int incrementAtomic(){
(*_atomicCounter)++;
int value = *_atomicCounter;
return value;
}
};
TEST(ConceptSink, IntCall__TwoCalls_ExpectingTwoAdd) {
std::atomic<int> counter{0};
{
std::unique_ptr<g2::LogWorker> worker{g2::LogWorker::createWithNoSink()};
auto handle = worker->addSink(std2::make_unique<IntReceiver>(&counter), &IntReceiver::receiveMsg);
std::future<int> intFuture1 = handle->call(&IntReceiver::incrementAtomic);
EXPECT_EQ(intFuture1.get(), 1);
EXPECT_EQ(counter, 1);
auto intFuture2 = handle->call(&IntReceiver::incrementAtomic);
EXPECT_EQ(intFuture2.get(), 2);
}
EXPECT_EQ(counter, 2);
}