2013-12-16 06:29:26 +01:00
|
|
|
/** ==========================================================================
|
|
|
|
* 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.
|
2016-08-11 08:27:52 +02:00
|
|
|
*
|
2014-07-03 23:42:19 +02:00
|
|
|
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
|
2013-12-16 06:29:26 +01:00
|
|
|
* ============================================================================*/
|
|
|
|
|
2013-11-15 10:02:30 +01:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
#include <atomic>
|
|
|
|
#include <chrono>
|
2013-11-15 10:02:30 +01:00
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <thread>
|
2023-12-01 00:17:45 +01:00
|
|
|
#include <vector>
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
#include "g3log/generated_definitions.hpp"
|
|
|
|
#include "g3log/logmessage.hpp"
|
2015-07-16 09:55:23 +02:00
|
|
|
#include "g3log/sink.hpp"
|
|
|
|
#include "g3log/sinkhandle.hpp"
|
2023-12-01 00:17:45 +01:00
|
|
|
#include "g3log/sinkwrapper.hpp"
|
|
|
|
#include "testing_helpers.h"
|
2013-11-15 10:02:30 +01:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace testing_helpers;
|
|
|
|
|
|
|
|
class CoutSink {
|
|
|
|
stringstream buffer;
|
|
|
|
unique_ptr<ScopedOut> scope_ptr;
|
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
CoutSink() :
|
|
|
|
scope_ptr(std::make_unique<ScopedOut>(std::cout, &buffer)) {}
|
|
|
|
|
|
|
|
public:
|
2013-11-15 10:02:30 +01:00
|
|
|
void clear() { buffer.str(""); }
|
|
|
|
std::string string() { return buffer.str(); }
|
2015-07-20 07:10:56 +02:00
|
|
|
void save(g3::LogMessageMover msg) { std::cout << msg.get().message(); }
|
2013-11-15 10:02:30 +01:00
|
|
|
virtual ~CoutSink() final {}
|
2023-12-01 00:17:45 +01:00
|
|
|
static std::unique_ptr<CoutSink> createSink() { return std::unique_ptr<CoutSink>(new CoutSink); }
|
2013-11-15 10:02:30 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct StringSink {
|
|
|
|
std::string raw;
|
2023-12-01 00:17:45 +01:00
|
|
|
void append(g3::LogMessageMover entry) { raw.append(entry.get().message()); }
|
2013-11-15 10:02:30 +01:00
|
|
|
std::string string() {
|
|
|
|
return raw;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
2015-07-20 07:10:56 +02:00
|
|
|
typedef std::shared_ptr<g3::internal::SinkWrapper> SinkWrapperPtr;
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
2015-07-20 07:10:56 +02:00
|
|
|
namespace g3 {
|
2013-11-15 10:02:30 +01:00
|
|
|
|
|
|
|
class Worker {
|
2023-12-01 00:17:45 +01:00
|
|
|
std::vector<SinkWrapperPtr> _container; // should be hidden in a pimple with a bg active object
|
2013-11-15 10:02:30 +01:00
|
|
|
std::unique_ptr<kjellkod::Active> _bg;
|
|
|
|
|
|
|
|
void bgSave(std::string msg) {
|
|
|
|
for (auto& sink : _container) {
|
2015-07-20 07:10:56 +02:00
|
|
|
g3::LogMessage message("test", 0, "test", DEBUG);
|
2013-11-15 10:02:30 +01:00
|
|
|
message.write().append(msg);
|
|
|
|
sink->send(LogMessageMover(std::move(message)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
public:
|
|
|
|
Worker() :
|
|
|
|
_bg{
|
|
|
|
kjellkod::Active::createActive()} {
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~Worker() {
|
|
|
|
_bg->send([this] {
|
2016-08-11 08:27:52 +02:00
|
|
|
_container.clear();
|
|
|
|
});
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void save(std::string msg) {
|
|
|
|
_bg->send([this, msg] { bgSave(msg); });
|
|
|
|
}
|
2016-08-11 08:27:52 +02:00
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
template <typename T, typename DefaultLogCall>
|
|
|
|
std::unique_ptr<SinkHandle<T>> addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
|
|
|
auto sink = std::make_shared<internal::Sink<T>>(std::move(unique), call);
|
|
|
|
auto add_sink_call = [this, sink] {
|
|
|
|
_container.push_back(sink);
|
|
|
|
};
|
2015-07-20 07:10:56 +02:00
|
|
|
auto wait_result = g3::spawn_task(add_sink_call, _bg.get());
|
2013-11-15 10:02:30 +01:00
|
|
|
wait_result.wait();
|
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
auto handle = std::make_unique<SinkHandle<T>>(sink);
|
2013-11-15 10:02:30 +01:00
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-12-01 00:17:45 +01:00
|
|
|
} // namespace g3
|
2014-01-20 06:55:44 +01:00
|
|
|
|
2015-07-20 07:10:56 +02:00
|
|
|
using namespace g3;
|
|
|
|
using namespace g3::internal;
|
2013-11-15 10:02:30 +01:00
|
|
|
|
|
|
|
TEST(ConceptSink, CreateHandle) {
|
|
|
|
Worker worker;
|
|
|
|
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
|
|
|
ASSERT_NE(nullptr, handle.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConceptSink, OneSink__VerifyMsgIn) {
|
|
|
|
Worker worker;
|
|
|
|
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
|
|
|
worker.save("Hello World!");
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
auto output = handle->call(&CoutSink::string);
|
|
|
|
auto content = output.get();
|
|
|
|
auto pos = content.find("Hello World!");
|
|
|
|
ASSERT_NE(pos, std::string::npos);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConceptSink, DualSink__VerifyMsgIn) {
|
|
|
|
Worker worker;
|
|
|
|
auto h1 = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
2018-02-21 06:02:19 +01:00
|
|
|
auto h2 = worker.addSink(std::make_unique<StringSink>(), &StringSink::append);
|
2013-11-15 10:02:30 +01:00
|
|
|
worker.save("Hello World!");
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
auto first = h1->call(&CoutSink::string);
|
|
|
|
auto second = h2->call(&StringSink::string);
|
|
|
|
|
|
|
|
ASSERT_EQ("Hello World!", first.get());
|
|
|
|
ASSERT_EQ("Hello World!", second.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ConceptSink, DeletedSink__Exptect_badweak_ptr___exception) {
|
2018-02-21 06:02:19 +01:00
|
|
|
auto worker = std::make_unique<Worker>();
|
2013-11-15 10:02:30 +01:00
|
|
|
auto h1 = worker->addSink(CoutSink::createSink(), &CoutSink::save);
|
|
|
|
worker->save("Hello World!");
|
|
|
|
worker.reset();
|
|
|
|
|
|
|
|
auto first = h1->call(&CoutSink::string);
|
|
|
|
EXPECT_THROW(first.get(), std::bad_weak_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
2016-08-11 08:27:52 +02:00
|
|
|
using AtomicBooleanPtr = std::shared_ptr<std::atomic<bool>>;
|
2023-12-01 00:17:45 +01:00
|
|
|
using AtomicIntegerPtr = std::shared_ptr<std::atomic<int>>;
|
|
|
|
using BoolList = std::vector<AtomicBooleanPtr>;
|
2016-08-11 08:27:52 +02:00
|
|
|
using IntVector = std::vector<AtomicIntegerPtr>;
|
2023-12-01 00:17:45 +01:00
|
|
|
} // namespace
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
TEST(ConceptSink, OneHundredSinks_part1) {
|
2013-11-15 10:02:30 +01:00
|
|
|
BoolList flags;
|
|
|
|
IntVector counts;
|
|
|
|
|
|
|
|
size_t NumberOfItems = 100;
|
|
|
|
for (size_t index = 0; index < NumberOfItems; ++index) {
|
2023-12-01 00:17:45 +01:00
|
|
|
flags.push_back(make_shared<atomic<bool>>(false));
|
|
|
|
counts.push_back(make_shared<atomic<int>>(0));
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto worker = std::unique_ptr<Worker>(new Worker);
|
|
|
|
size_t index = 0;
|
|
|
|
for (auto& flag : flags) {
|
|
|
|
auto& count = counts[index++];
|
|
|
|
// ignore the handle
|
2018-02-21 06:02:19 +01:00
|
|
|
worker->addSink(std::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
worker->save("Hello to 100 receivers :)");
|
|
|
|
worker->save("Hello to 100 receivers :)");
|
|
|
|
}
|
2016-08-11 08:27:52 +02:00
|
|
|
// at the curly brace above the ScopedLogger will go out of scope and all the
|
2013-11-15 10:02:30 +01:00
|
|
|
// 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(2 == count->load()) << ", count : " << (index - 1);
|
|
|
|
}
|
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
cout << "test one hundred sinks is finished\n";
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
TEST(ConceptSink, OneHundredSinks_part2) {
|
2023-12-01 00:17:45 +01:00
|
|
|
using BoolPtrVector = std::vector<AtomicBooleanPtr>;
|
|
|
|
using IntPtrVector = vector<AtomicIntegerPtr>;
|
2016-08-11 08:27:52 +02:00
|
|
|
BoolPtrVector flags;
|
|
|
|
IntPtrVector counts;
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2017-03-26 09:11:18 +02:00
|
|
|
int NumberOfItems = 100;
|
|
|
|
for (int index = 0; index < NumberOfItems; ++index) {
|
2016-08-11 08:27:52 +02:00
|
|
|
flags.push_back(make_shared<atomic<bool>>(false));
|
|
|
|
counts.push_back(make_shared<atomic<int>>(0));
|
|
|
|
}
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
{
|
|
|
|
auto worker = g3::LogWorker::createLogWorker();
|
|
|
|
size_t index = 0;
|
|
|
|
for (auto& flag : flags) {
|
2023-12-01 00:17:45 +01:00
|
|
|
auto& count = counts[index++];
|
2016-08-11 08:27:52 +02:00
|
|
|
// ignore the handle
|
2018-02-21 06:02:19 +01:00
|
|
|
worker->addSink(std::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
2016-08-11 08:27:52 +02:00
|
|
|
}
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
// 100 logs
|
2023-12-01 00:17:45 +01:00
|
|
|
for (int index = 0; index < NumberOfItems; ++index) {
|
|
|
|
LogMessagePtr message{std::make_unique<LogMessage>("test", 0, "test", DEBUG)};
|
|
|
|
message.get()->write().append("Hello to 100 receivers :)");
|
|
|
|
worker->save(message);
|
|
|
|
}
|
|
|
|
} // RAII exit
|
2013-11-15 10:02:30 +01:00
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
// 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 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) {
|
2013-11-15 10:02:30 +01:00
|
|
|
auto& count = counts[index++];
|
2016-08-11 08:27:52 +02:00
|
|
|
EXPECT_TRUE(flag->load());
|
2023-12-01 00:17:45 +01:00
|
|
|
EXPECT_EQ(NumberOfItems, count->load());
|
2016-08-11 08:27:52 +02:00
|
|
|
}
|
2013-11-15 10:02:30 +01:00
|
|
|
}
|
|
|
|
|
2016-08-11 08:27:52 +02:00
|
|
|
TEST(ConceptSink, OneSinkWithHandleOutOfScope) {
|
|
|
|
AtomicBooleanPtr flag = make_shared<atomic<bool>>(false);
|
|
|
|
AtomicIntegerPtr count = make_shared<atomic<int>>(0);
|
|
|
|
{
|
|
|
|
auto worker = g3::LogWorker::createLogWorker();
|
|
|
|
{
|
2023-12-01 00:17:45 +01:00
|
|
|
auto handle = worker->addSink(std::make_unique<ScopedSetTrue>(flag, count), &ScopedSetTrue::ReceiveMsg);
|
2016-08-11 08:27:52 +02:00
|
|
|
}
|
|
|
|
EXPECT_FALSE(flag->load());
|
|
|
|
EXPECT_TRUE(0 == count->load());
|
|
|
|
|
2018-02-21 06:02:19 +01:00
|
|
|
LogMessagePtr message{std::make_unique<LogMessage>("test", 0, "test", DEBUG)};
|
2016-08-11 08:27:52 +02:00
|
|
|
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());
|
|
|
|
}
|